在下面的例子中,我的对象超出了范围,我访问了一个无效的指针:
struct Animal
{
char* buffer;
Animal() { buffer = new char[100]; }
~Animal() { delete[]buffer; }
};
int main()
{
vector<Animal> list;
{
Animal dog;
list.push_back(dog);
}
list[0].buffer[50] = 7; // Buffer's been deleted, can't access it
}
我想防止这种情况的最好方法是在向量中构建Animal对象,但我不知道该怎么做。我想过要做:
list.push_back(Dog());
但这仍然会产生一个暂时的,除非它被优化掉了,我宁愿不依赖它,因为在另一个地方(另一个编译器),它可能不会做同样的事情。
编辑:感谢Remy Lebeau我已经了解到你可以直接在向量中构造一个向量元素,没有临时性,没有复制,具有以下功能:
template< class... Args >
void emplace_back( Args&&... args );
我不知道可变参数模板参数是如何工作的,但描述是:
将新元素追加到容器的末尾。元素是 通过std :: allocator_traits :: construct构造,通常是 使用placement-new在该位置就地构造元素 由容器提供。参数args ...被转发给 构造函数为std :: forward(args)....
答案 0 :(得分:3)
问题不在于临时性超出范围。真正的问题是,Animal
违反了Rule of three,没有实现复制构造函数或复制赋值运算符。
当您将临时文件推入向量时,会生成对象的副本,但编译器生成的复制构造函数只是按原样复制指针,它不会分配内存的副本。因此,当临时文件被销毁时,内存将在析构函数中释放,并且副本会留下一个指向无效内存的悬空指针。
添加复制构造函数以分配新内存:
struct Animal
{
char* buffer;
Animal() {
buffer = new char[100];
}
Animal(const Animal &src) {
buffer = new char[100];
std::copy(src.buffer, src.buffer+100, buffer);
}
~Animal() {
delete[] buffer;
}
Animal& operator=(const Animal &rhs) {
if (this != &rhs) {
std::copy(rhs.buffer, rhs.buffer+100, buffer);
}
return *this;
}
};
或者,使用std::vector
而不是原始指针,让编译器为您生成合适的复制构造函数,复制赋值运算符和析构函数:
struct Animal
{
std::vector<char> buffer;
Animal() : buffer(100) {}
};
或者,只需静态分配内存而不是动态分配:
struct Animal
{
char buffer[100];
};