在移动/复制c ++对象实例时

时间:2011-11-02 23:45:56

标签: c++

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

在查看我在计算机上维护的代码库时,我在LLVM的代码库中找到了一个类,它非常完美地描述了我正在寻找的内容:SmallVector.h。作为C ++的新手,我不完全确定为什么会做出一些设计决策。例如,为什么数组按U而不是T分配?评论给出了一个线索:

  

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

U当然是指以下联盟:

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

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

最佳, 杜安

3 个答案:

答案 0 :(得分:3)

你应该看一下标准库 allocators 背后的基本机制,它可以解决你可能遇到的很多问题!

这是基本的分配原则。我们分离内存分配和对象构造。正如您所观察到的那样,最重要的障碍是内存应该正确对齐对象:

// 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();

为了做你想到的,你可以使用我使用的char数组q并使它成为你的类的成员。也就是说,类总是随身携带一些构造对象的内存。

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

标准库分配器几乎可以做到这一点。

分离内存分配和对象构建是任何类型的高级内存管理,责任拥有类的核心。

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

答案 1 :(得分:1)

  

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

因为这是标准规定的要求。分配T数组意味着初始化每个元素。请注意,在C ++ 11中,char的对齐限制已经更改,因此“char数组很好”。

  

有没有办法在不调用这些构造函数/析构函数的情况下移动c ++对象实例,即进出向量?

是的,通过move-constructors /赋值运算符,它们也是C ++ 11的新手。有一个用于C ++ 03的模拟器库以及 Boost 中的移动支持容器。

答案 2 :(得分:0)

C ++ 11也有移动语义。如果在类中实现移动构造函数(比如Foo),std :: vector将会表现得更好。