关于移动/复制c++对象实例

On moving/copying c++ object instances

本文关键字:复制 c++ 对象 实例 于移动 移动      更新时间:2023-10-16

我试图在c++中创建一个类型无关的向量,它有两个区别。首先,它在对象本身中分配内存,至少直到某一点,而不是在堆上维护实际的对象数组。其次,它不能使用c++的复制/赋值构造函数,这似乎会减慢代码的速度,而且是不必要的。

在查看我在计算机上维护的代码库时,我在LLVM的代码库中发现了一个类,它非常完美地描述了我正在寻找的东西:SmallVector.h。作为c++的新手,我不完全确定为什么要做出一些设计决策。例如,为什么数组是按U而不是按T分配的?注释给出了一个提示:

如果T有一个tor或dr,我们不希望它自动运行,所以我们需要用其他东西来表示空间。char数组可以很好地工作,但可能没有充分对齐。相反,我们为空间使用一定数量的联合实例,这保证了最大的对齐。

U,当然是指以下并集:

union U {
    double D;
    long double LD;
    long long L;
    void *P;
} FirstEl;

所以,我猜,这是我真正的问题:为什么分配T数组意味着调用构造函数/析构函数?有没有办法移动c++对象实例,即进出矢量,而不调用这些构造函数/析构函数?我想我可以使用LLVM的SmallVector实现,但我讨厌在不理解它的情况下使用代码。

最好的,杜安

您应该看看标准库分配器背后的基本机制,它可以处理您可能遇到的许多问题!

这是基本的分配原则。我们将内存分配和对象构造分开。正如您所观察到的,最大的障碍是内存应该为对象正确对齐:

// getting memory
void * p = malloc(1000);  // version 1, system's allocator
char q[1000];             // automatic array, this is also memory :-)
// constructing an object
T * m_x1 = ::new (p) T;   // default-initialized
T * m_x2 = ::new (q) T(); // value-initialized
T * m_x3 = ::new (q + sizeof(T)) T(1, 'a'); // some specific constructor
// destroying the objects:
m_x1->~T();
m_x2->~T();
m_x3->~T();

要做你想做的,你可以把我使用的字符数组q,并使它成为你的类的成员。也就是说,类总是携带一些内存来构造对象。

实际的对象构造是使用全局place -new表达式完成的。回想一下,这样构造的对象必须手动销毁(这将是您的责任)。

标准库分配器做了类似的事情。

分离内存分配和对象构造是任何高级内存管理和责任归属类的核心。

注意,一旦在特定地址构造了对象,就不能移动周围的内存。对象很可能取决于它在内存中的位置!移动对象的唯一有效方法是复制/移动-构造一个新对象。

为什么分配数组T意味着调用构造函数/析构函数?

因为这是标准要求的。分配一个T数组意味着初始化它的每个元素。请注意,在c++ 11中,char的对齐限制已经改变,因此现在"一个char数组工作得很好"。

是否有任何方法移动c++对象实例,即进出向量,而不调用这些构造函数/析构函数?

可以,通过move构造函数/赋值操作符实现,这也是c++ 11的新特性。在Boost

中有一个c++ 03的模拟器库和支持移动的容器。

c++ 11也有移动语义。如果在类中实现移动构造函数(比如Foo), std::vector的性能会好得多。