我正在尝试用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
实现,但我讨厌使用代码而不理解它。
最佳, 杜安
答案 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将会表现得更好。