由于情况复杂(在前面的问题Constructing an object to return by value elsewhere中有解释),我想通过函数X的值返回一个对象,但在由X间接调用的另一个函数Y中创建它。在它们之间的调用堆栈中没有第三方代码在传递物体方面进行合作。 X只能将指针传递给Y并接收返回的指针。
我提出了一个使用new放置的解决方案,但主要担心它是否可移植,是否调用任何 undefined 的行为以及安全地处置分配的对象。为避免不必要的复制,也欢迎进行任何改进。这是一个完整的测试程序,该程序被编写为尽可能最小:
#include <new>
#include <type_traits>
#include <cstdio>
class A {
public:
A() {
printf("Create A @ %p\n", this);
}
A(const A &other) {
printf("Copy A @ %p\n", this);
printf("From another A %s @ %p\n", other.valid ? "OK" : "NOT OK", &other);
valid = other.valid;
}
A(A &&other) {
printf("Move A @ %p\n", this);
printf("From another A %s @ %p\n", other.valid ? "OK" : "NOT OK", &other);
valid = other.valid;
}
~A() {
printf("Destroy A %s @ %p\n", valid ? "OK" : "NOT OK", this);
valid = false;
}
void bar() {printf("Hello, World! (A %s @ %p)\n", valid ? "OK" : "NOT OK", this);}
bool valid = true;
};
class WrapA {
public:
WrapA() {printf("Create wrapper! (A @ %p)\n", &data);}
~WrapA() {
printf("Destroy wrapper! (A %s @ %p)\n", reinterpret_cast<A *>(&data)->valid ? "OK" : "NOT OK", &data);
// Manually call destructor for instance created using placement new
reinterpret_cast<A *>(&data)->~A();
}
void init() {
::new(&data) A();
}
A getA() {
printf("Wrapper returning A %s @ %p\n", reinterpret_cast<A *>(&data)->valid ? "OK" : "NOT OK", &data);
return(*reinterpret_cast<A *>(&data));
}
typename std::aligned_storage<sizeof(A), alignof(A)>::type data;
};
A debug(A data) {
printf("Wrapper returned A %s @ %p\n", data.valid ? "OK" : "NOT OK", &data);
return(data);
}
A test() {
WrapA wrapper;
wrapper.init();
return(debug(wrapper.getA()));
}
int main(void) {
test().bar();
return(0);
}
它打印:
Create wrapper! (A @ 0x7fff1d6a5bde)
Create A @ 0x7fff1d6a5bde
Wrapper returning A OK @ 0x7fff1d6a5bde
Copy A @ 0x7fff1d6a5bdf
From another A OK @ 0x7fff1d6a5bde
Wrapper returned A OK @ 0x7fff1d6a5bdf
Move A @ 0x7fff1d6a5c0f
From another A OK @ 0x7fff1d6a5bdf
Destroy A OK @ 0x7fff1d6a5bdf
Destroy wrapper! (A OK @ 0x7fff1d6a5bde)
Destroy A OK @ 0x7fff1d6a5bde
Hello, World! (A OK @ 0x7fff1d6a5c0f)
Destroy A OK @ 0x7fff1d6a5c0f
输出显示A通过3个不同的内存地址传递,在整个时间内一直保持有效,并且所有副本似乎都被正确销毁了。在该示例中,
test
直接调用init
,但在实际情况下,test
使用指向wrapper
变量的指针调用其他内容,最终wrapper.init
在其他地方被调用,从而接收到许多具有复杂生命周期的参数。用
WrapA::init
创建的对象是否安全地传递到main
并适当地用WrapA::~WrapA
处理?调用A::bar()
时一切正常吗?代码有问题吗? 最佳答案
您可以看一下管理诸如wrapA之类的资源的类,您基本上需要问两个问题:
让我们从1开始。我看到一些潜在的问题:
至于2:
简而言之,wrapA并不是完全错误的,因为您可以完美地使用它(如您所展示的)。但是,这也不完全正确。它不能满足您期望的c++类满足的要求,因此,我认为使用wrapA编写错误代码很容易。我认为,如果您解决有关析构函数以及复制构造函数/赋值的问题,使用它会更加安全。
关于c++ - 全新放置,按值(value)返回并安全处置临时拷贝,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31091223/