c++ - 这个类模板中的这个函数模板是干什么的?

标签 c++

我正在研究我正在阅读的一本书中的 C++ 类模板,虽然大部分内容都很清楚,但这个特定的函数确实让我很烦:

template <typename T> 
struct Vector3 {

T x; T y; T z;

//... several methods, constructors, etc

//Then this one, which is really confusing me:

template <typename P> 
P* Write(P* pData)
   {
    Vector3<T>* pVector = (Vector3<T>*) pData; 
    *pVector++ = *this;
    return (P*) pVector;
   }

首先,这个函数似乎在处理一个 P 数组或一个指向 P 的指针,就好像它可以很容易地从指向 Vector3 的指针进行转换一样。 , 类的名称。怎么样?如果我有一个 Vector3<float> someVector , 是什么指向这个 someVector可转换为指向 float 的指针? (甚至 int ?)它也做相反的事情:为函数提供一个 float 组,然后它可以将它转换为 Vector3 的数组。 .

所以这是我感到困惑的第一个方面。

接下来是 *pVector++ = *this; -- 我认为这是指针算法,如果 pVector指向数组中的第二个元素,使用此表达式,我们将指针递增到数组的下一个元素,但只有 after 我们首先分配 *this pVector指向的当前元素.假设我在这方面是正确的,不会 pVector总是指向数组中的第一个元素,因为它只是在上一行创建的?! ++ 的目的是什么?在这种情况下的运营商?

最佳答案

让我们分解一下它是如何工作的:

  1. 这是函数声明。重要的一点是 PT 无关.所以,我们需要多加注意,因为可能会发生一些不好的事情......

    template <typename P> 
    P* Write(P* pData)
    {
    

    让我们代表pData指向的内存.为了便于解释,我假设 pData指向内存中足够大的区域(否则 Write 可能会导致段错误),并且 Vector3<T>只有 3 T 的大小秒。下面我取T = float , 与 sizeof(float) = 4 ,但我的解释对其他类型仍然有效。所以,这里 sizeof(Vector3<float>) = 12 .

    所以,这是内存,|-|是一个字节:

    |-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|
    ^
    |
    pData : P*
    
  2. 我们解读pData作为指向 Vector3<T> 的指针.这是一种糟糕的风格一般,如P可以是任何东西。

        Vector3<T>* pVector = (Vector3<T>*) pData; 
    
  3. 下面一行:

        *pVector++ = *this;
    

    可分为:

        *pVector = *this;
        pVector++;
    
    • *pVector = *this;将 vector ( *this) 的内容分配给数据。现在的内存是:

      pVector : Vector3<float>*
      |
      v
      |X|X|X|X|Y|Y|Y|Y|Z|Z|Z|Z|-|-|-|-|-|
      ^^^^^^^^^^^^^^^^^^^^^^^^^
      copied content of the vector
      
    • pVector++;将 vector 递增 1 * sizeof(Vector3<float>) ,所以它现在指向尚未写入的内存:

                              pVector : Vector3<float>*
                              |
                              v
      |X|X|X|X|Y|Y|Y|Y|Z|Z|Z|Z|-|-|-|-|-|
      
  4. pVector被投回 P*并返回。

        return (P*) pVector;
    }
    

    这使得链式写入成为可能,因为对返回指针的写入不会覆盖第一次写入:

    char data[2 * sizeof(Vector3<float>)];
    v2.Write(v1.Write(data));
    // now data is:
    //                                                 contents of v2
    //                                     vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
    // |X1|X1|X1|X1|Y1|Y1|Y1|Y1|Z1|Z1|Z1|Z1|X2|X2|X2|X2|Y2|Y2|Y2|Y2|Z2|Z2|Z2|Z2
    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    //          contents of v1
    

现在,一些缺陷:

这个函数对io很有用,相当于一个memcpy在 vector 上。然而,它有很多缺陷,主要的一个是模板参数。直接写入内存进行此类操作应使用 char ,而不是别的东西。在内存中写入以覆盖类的内容(即,不是 io)是非常糟糕的做法,(赋值运算符是为此类任务而创建的,它们更安全)。此外,以下示例不是自描述的:

vec.Write<MyTimerClass>(pointer); // Does not make sense if you are reading this line for the first time

其次,内存复制存在问题。在这里,在解释中,我假设 Vector3是一个简单的类型。情况并非总是如此。如果它有虚函数和不同大小的成员,内存中的布局将由实现定义,例如:

                 X, Y, Z            padding
        ------------------------    ----
|P|P|P|P|X|X|X|X|Y|Y|Y|Y|Z|Z|Z|Z|a|a|.|.
--------                        ----
 vtable                         some
 pointer                        other
                                member

这对 io 来说是不可靠的。参见 this SO question (公认的答案是:“这是 for msvc 的工作方式”...)。对于多重虚拟继承,它变成了真正的噩梦。

顺便说一句,这种方法的安全实现应该是这样的:

template<typename IOBuffer>
bool Write(IOBuffer& buffer)
{
    return buffer << X << Y << Z;
}

或更好:

virtual bool Write(IOBufferInterface& buffer)
{
    return buffer << X << Y << Z;
}

它更易于理解、维护、调试等...

关于c++ - 这个类模板中的这个函数模板是干什么的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15999363/

相关文章:

C++ 重写一个成员变量

java - 与 “JAVA exception handling mindset”相比, “C++ exception handling”是什么?

c++ - OpenGL 相机 vector

C++ MySQL 连接器库运行时错误

c++ - 等效于 MEL setKeyframe 的 Maya C++ API

c++ - 如何使用QPixmap使得地址中只需要使用项目文件夹

c++ - 使用 CascadeClasifier 与 FaceRecognizer (FisherFace) 的 OpenCV 性别分类

c++ - "unsigned int"是否被视为一种数据类型?

c++ - 如何在 C++ 中重载一元和二元减号运算符?

c++ - PoCo 日志记录。包含创建时间戳的日志文件名或每次应用程序启动时的新日志文件