如果你有一个没有析构函数的类:
struct A {
~A() = delete;
};
标准不允许我“本地”分配该类的实例:
int main()
{
A a; //error
}
但是如果我在免费商店分配它似乎没问题:
int main()
{
a *p = new A();
}
只要我不在该指针上调用delete:
int main()
{
a *p = new A();
delete p; //error
}
所以我的问题是,如果我在免费商店分配它,为什么标准让我有一个没有析构函数的类?我猜有一些用例吗?但到底是什么?
答案 0 :(得分:7)
所以我的问题是,如果我在免费商店分配它,为什么标准让我有一个没有析构函数的类?
因为标准功能不起作用。
您正在谈论的= delete
语法是为了解决许多问题而发明的。其中一个非常具体:制作只移动或不移动的类型,如果您试图调用复制(或移动)构造函数/赋值运算符,编译器将issue a compile-time error。
但一般情况下,语法有其他用途。通过=delete
函数,可以防止人们调用函数的特定重载,主要是为了阻止某些有问题的隐式转换。如果您不调用具有特定类型的函数,则会因调用delete
d重载而出现编译时错误。因此,=delete
可以应用于任何函数。
类的析构函数符合"任何函数"。
该功能的设计意图不是制作不可破坏的类型。这只是允许=delete
任何功能的结果。它不是设计或意图;它就是。
虽然将=delete
应用于析构函数并没有多大用处,但在规范中明确禁止使用它时,也没有多大用处。析构函数。当应用于析构函数时,当然在使=delete
行为方式上有很大用处。
答案 1 :(得分:5)
有了这个:
A a;
您将在退出范围时调用析构函数(并且已删除析构函数,因此错误)。有了这个:
A *a = new A();
你根本就没有调用析构函数(因为你从不使用delete
)。在程序完成时清理内存,但实质上是保证内存泄漏。
c++
没有理由不允许这种行为,因为这会创建一个非常具体的案例来编程到编译器中。例如,c++
不允许这样做:
int *p; *p = 5;
尽管这显然很糟糕,但总是很糟糕。程序员应该确保他们不这样做。
没有理由删除析构函数,因为它不是一种有用的行为。
答案 2 :(得分:1)
在多线程环境中,您可能在线程之间共享非破坏类 如果分配内存的线程终止,则没有理由指向该分配的内存的指针仍然不能被另一个线程使用。
标准意味着具有动态存储持续时间的构造对象不符合析构函数调用的条件。
12.4析构函数[class.dtor]
隐式调用析构函数
- 对于在程序终止时具有静态存储持续时间的构造对象,
- 对于具有线程存储持续时间的构造对象 在线程出口处,
- 对于具有自动的构造对象 创建对象的块时的存储持续时间 退出,
- 对于构造的临时对象 终身结束。
我们可以通过线程之间的基本内存共享示例看到这样做的好处:
#include <thread>
#include <iostream>
//shared object
struct A {
void say_hello(){ std::cout << ++value << '\n'; }
~A() = delete;
int value;
};
//two threads
void creator();
void user(A* a);
//the creator allocates memory,
//gives it to another thread (via pointer),
//and then ends gracefully.
//It does not attempt to implicitly call the destructor.
//Nor would we want it to for allocated memory we are sharing.
void creator(){
A* a = new A();
a->value = 0;
std::thread t(user, a);
t.detach();
}
//The user recieves a pointer to memory,
//and is free to continue using it
//despite the creator thread ending
void user(A* a){
while(1){
a->say_hello();
}
}
//main->creator->user
int main(){
std::thread t(creator);
while(1){}
}