我是否可以传递对未初始化内存的引用,获取地址,然后调用pass new或在获得的内存位置上调用析构函数。换句话说,下面的程序是合法的行为还是有未定义的行为:
#include <string>
#include <iostream>
void ctor (std::string &s)
{
new (&s) std::string ("Hello, world!");
}
void dtor (std::string &s)
{
(&s)->std::string::~string ();
}
int main ()
{
std::string * memory = static_cast<std::string *> (
operator new (sizeof (std::string) * 10));
ctor (memory [0]);
std::cout << memory [0] << '\n';
dtor (memory [0]);
operator delete (memory);
}
当然,它是有效的,并且我尝试了gcc的未定义行为消毒器,它没有产生任何错误。但有没有人能根据这个标准来证实/反驳呢?
发布于 2017-12-25 20:07:12
上面的代码在[0]
双重构造一个字符串,这是一个潜在的资源泄漏,然后双重销毁它,这是未定义的行为。
new string[10]
在数组中构造对象。delete[]
将销毁这些对象。您在另一个对象之上创建一个新对象,然后销毁它,然后在delete[]
时再次销毁它。
其他的看起来都没问题;我的意思是它使用了原始分配,这通常是不好的做法,代码是异常的不安全的,等等。
发布于 2017-12-25 20:07:38
dtor (memory [0]);
delete [] memory;
绝对是未定义的行为。
在行中构造的对象的生存期
std::string * memory = new std::string [10];
在使用placement new运算符时结束。
因此,
delete [] memory;
是未定义的行为。
更新
更新后的代码行
dtor (memory [0]);
operator delete (reinterpret_cast<void *> (memory));
举止得体。
使用放置新操作符分配的对象的析构函数只被调用一次。
operator delete
调用将释放由operator new
调用分配的内存。
发布于 2017-12-25 23:36:58
编辑后,似乎不再有未定义的行为。
但是,您的代码中仍然存在危险
您的memory
变量具有指向构造字符串的指针的类型,即使在初始化指针后该指针后面没有字符串。指针也不是nullptr
。这很危险。你是在向编译器断言某些东西是正确构造的对象,而事实并非如此,因此,编译器不会在错误地使用未构造的对象时抓到你。
我强烈建议使用char*
变量跟踪未初始化的内存,并且只对已经正确构造的对象使用类类型指针。
https://stackoverflow.com/questions/47971664
复制