作为学术练习,我创建了一个自定义向量实现,我希望支持复制非pod类型。如何最好地处理未初始化内存的可交换成语
我希望容器支持不提供默认构造函数的存储元素。
当我为向量保留内存,然后push_back一个元素(它管理它自己的资源并且实现了复制和赋值操作符 - 我忽略了当前的构造函数)我有一个使用copy-交换该类型的成语。
由于交换发生在仍为未初始化内存的类型上,所以在交换之后,被临时调用的析构函数将尝试释放某些未初始化的数据,这当然会激化。
我可以看到几种可能的解决方案。一种是确保所有非pod类型都实现默认构造函数,并在集合中的每个元素上调用该元素(放置新元素)。我不是这个想法的粉丝,因为它看起来既浪费又麻烦。
另一种方法是在执行交换之前将容器中类型空间的内存mem设置为0(这样临时值将为空,调用析构函数将无误地运行)。这对我来说有点不好意思,我不确定是否有更好的选择(请参阅下面的代码以获得一个示例)。您也可以在为一堆元素调用reserve后将所有保留空间memset设置为0,但这可能是浪费。
是否有关于如何实现std :: vector的文档,因为调用reserve不会调用分配元素的构造函数,而resize会调用(并且对于未实现默认构造函数的构造函数,构造的临时变量可以作为第二个参数调用)
下面是一些代码可以运行来演示问题,我省略了实际的向量代码,但原理保持不变。
#include <iostream>
#include <cstring>
// Dumb example type - not something to ever use
class CustomType {
public:
CustomType(const char* info) {
size_t len = strlen(info) + 1;
info_ = new char[len];
for (int i = 0; i < len; ++i) {
info_[i] = info[i];
}
}
CustomType(const CustomType& customType) {
size_t len = strlen(customType.info_) + 1;
info_ = new char[len];
for (int i = 0; i < len; ++i) {
info_[i] = customType.info_[i];
}
}
CustomType& operator=(CustomType customType) {
swap(*this, customType);
return *this;
}
void swap(CustomType& lhs, CustomType& rhs) {
std::swap(lhs.info_, rhs.info_);
}
~CustomType() {
delete[] info_;
}
char* info_;
};
int main() {
CustomType customTypeToCopy("Test");
// Mimics one element in the array - uninitialised memory
char* mem = (char*)malloc(sizeof(CustomType));
// Cast to correct type (would be T for array element)
CustomType* customType = (CustomType*)mem;
// If memory is cleared, delete[] of null has no effect - all good
memset(mem, 0, sizeof(CustomType));
// If the above line is commented out, you get malloc error - pointer
// being freed, was not allocated
// Invokes assignment operator and copy/swap idiom
*customType = customTypeToCopy;
printf("%s\n", customType->info_);
printf("%s\n", customTypeToCopy.info_);
return 0;
}
任何信息/建议将不胜感激!
解决!
感谢@Brian和@Nim帮助我理解赋值(复制/交换)有效时的用例。
为了达到我想要的东西,我只是需要更换线路
*customType = customTypeToCopy;
与
new (customType) CustomType(customTypeToCopy);
调用拷贝构造函数没有赋值操作符!
谢谢!
我已经读了几次这个问题(可能是迟到了),但不清楚你是否有执行交换的自定义类型*或矢量*的问题? (顺便说一句,我不认为'memset()'会起作用)并且不清楚在单元化内存中使用copy-swap的原因(意味着你试图访问一个超出vector的“bounds”范围的元素...) – Nim
嘿Nim!对不起,如果我的解释不是很好,我会尽力澄清。基本上,在交换时,位于未初始化内存值的info_指针会被移入临时进入该函数的临时位置,然后当作用域结束时,该临时对象会调用析构函数,但info_指针只是垃圾,所以调用delete []会导致崩溃。如果我以前memset内存,它将为空,并且调用delete不起作用。我只想知道这是一件好事还是坏习惯。我想不出一个好的选择:( – Tom
...但这意味着你*交换*的元素是*出界*(即超出矢量的*大小*) – Nim