我想确保对象的析构函数不运行。有没有办法做到这一点,除了把对象放在堆上而不是调用delete?
答案 0 :(得分:7)
Not recommended,但这是另一种方式:
char buffer[sizeof(T) + alignof(T)];
char* aligned_buffer = buffer + alignof(T) - reinterpret_cast<intptr_t>(buffer) % alignof(T);
T* object = new (aligned_buffer) T;
但是,虽然这意味着编译器不会自动调用析构函数,但程序员仍然可以:
object->~T();
当然,堆分配也是如此:
delete object;
为了防止这种情况,您必须使析构函数不可访问:
struct T
{
private:
~T() {};
};
或者真的无法访问(相关:Why must a base class destructor be accessible only when a custom constructor is declared?):
class indestructible_base
{
~indestructible_base();
};
struct T : indestructible_base
{
};
答案 1 :(得分:2)
如果你想在调用析构函数时发生错误,那么就不要为它提供一个定义:
struct foo {
~foo();
};
或delete
它在C ++ 11中:
struct foo {
~foo() = delete;
};
如果你有时只想要它被调用,那么你几乎肯定需要重新考虑你的设计。没有“安全”的方法,虽然使用new
而不删除可能会有效,但我强烈建议你不要这样做。
或者,如果您有时需要某些析构函数行为,则可以添加标志:
struct foo {
foo(bool destroy = true) : destroy(destroy) {}
~foo() {
if(destroy) {
// destruction stuff here
}
}
bool destroy;
};
答案 2 :(得分:1)
另一种方式是placement new
运营商。
答案 3 :(得分:1)
按照std::optional的操作方式,您可以创建自己的更简单的对象包装器模板:
#include <iostream>
template <typename T_>
struct Wrapper
{
union {
char dummy_;
T_ value_;
};
bool shouldDestroy_ {true};
template<typename ...Args>
Wrapper(Args &&... args) :
value_(std::forward<Args>(args)...)
{
}
const T_ &value() const { return value_; }
T_ &value() { return value_; }
const T_ *get() const { return &value_; }
T_ *get() { return &value_; }
const T_ *operator->() const { return get(); }
T_ *operator->() { return get(); }
void destroy(bool destroy) { shouldDestroy_ = destroy; }
~Wrapper()
{
if (shouldDestroy_) {
value_.~T_();
}
}
};
int main()
{
struct Foo
{
Foo() { std::cout << "Foo()\n"; }
Foo(int value) { std::cout << "Foo(" << value << ")\n"; }
~Foo() { std::cout << "~Foo()\n"; }
void display(const char *str) { std::cout << str << "\n"; }
};
std::cout << "Running...\n";
// example 1 construct/destructed
{
Wrapper<Foo> a;
a.value().display("via value 1");
a->display("via operator 1");
}
// example 2 construct/destructed
{
Wrapper<Foo> a(2);
a.value().display("via value 2");
a->display("via operator 2");
}
// example 3 construct NOT destructed
{
Wrapper<Foo> a(3);
a.value().display("via value 3");
a->display("via operator 3");
// do not allow destroy
a.destroy(false);
}
return 0;
}
输出将如下所示:
Running...
Foo()
via value 1
via operator 1
~Foo()
Foo(2)
via value 2
via operator 2
~Foo()
Foo(3)
via value 3
via operator 3
答案 4 :(得分:1)
我很惊讶没有人用union
提到完全符合C ++标准的解决方案。在union
中,没有自动为成员调用构造函数,甚至没有析构函数。即使在工会中只有一个成员的情况下。所有这些都必须“手动”完成:
构造函数可以通过所谓的“ placement new”(或从:
引入的构造函数初始化列表中调用)
析构函数。
演示:
class MyObj {
int i;
public:
MyObj(int i_) : i(i_) { std::cout << i << " constructed" << std::endl; }
MyObj(MyObj const &src) : i(src.i + 100) { std::cout << src.i << " copied to new " << i << std::endl; }
~MyObj() { std::cout << i << " destroyed" << std::endl; }
};
class OptDestr {
bool callDestructor;
union { MyObj o; }; // Only allocated, but no constr/destr is called automatically
public:
// Constructor
OptDestr(int i, bool callDestructor_) : callDestructor(callDestructor_),
o(i) // calls MyObj constructor
{ }
// OR alternatively:
OptDestr(int i, bool callDestructor_) : callDestructor(callDestructor_) {
new (&o)MyObj(i); // placement new - does NOT allocate, just calls constructor
}
// Copy constructor
OptDestr(OptDestr const &src) : callDestructor(src.callDestructor),
o(src.o) // explicit call of MyObj copy-constructor
{ }
// OR alternatively:
OptDestr(OptDestr const &src) : callDestructor(src.callDestructor) {
new (&o)MyObj(src.o); // placement new - no allocation, just explicitly calls copy-constructor of MyObj
}
// Destructor
~OptDestr() {
if (callDestructor) o.~MyObj(); // explicit call of destructor
}
};
int main() {
OptDestr d1(1, false /*callDestructor*/);
OptDestr d1_copy(d1);
OptDestr d2(2, true /*callDestructor*/);
OptDestr d2_copy(d2);
}
程序的输出如下:
1 constructed
1 copied to new 101
2 constructed
2 copied to new 102
102 destroyed
2 destroyed
您可以看到1 destructed
和101 destructed
都不存在。我猜想像std::Optional
这样的类型是以类似的方式实现的。