C++11 析构函数 = 删除
C++11 Destructor = delete
我看到了 constructor = delete 的解释 here 但我想知道我是否也应该禁止析构函数调用。我正在尝试使用这样的 class:
class A
{
public:
static bool foo(const char* filePath);
static void foo(const int something);
private:
A() = delete;
~A();
};
我也应该写成~A() = delete;
吗?这有关系吗?
不,没关系。你也可以删除它,但是如果删除了构造函数,那么删除析构函数将不会做任何额外的事情。
第一个(已删除的构造函数)表明无法创建对象。第二个(已删除的析构函数)表示无法销毁对象。
请注意,可以使用各种 hack "create" 和初始化对象,但在那些情况下,所有的赌注都没有了,并且程序正在执行未定义的行为。
~A() = delete;
是多余的,因为你不能创建一个对象,所以没有必要担心析构函数。
事实上,对于您的代码,甚至不需要 A() = delete;
,因为所有 class 成员都是 static
。
正如 Luchian 在评论中正确提到的那样,这样的 class
最好声明为 namespace
。底层数据可以根据需要做成extern
/static
(注意:在C++20中,删除聚合的构造函数现在使得类型无法构造,因此不再有意外行为)
要在此处添加其他答案,您可能希望将析构函数声明为已删除而不是私有且未实现。这是因为,即使使用 private
删除的构造函数,您仍然可以使用 聚合初始化 来创建实例:
Demo
class A
{
public:
static bool foo(const char* filePath);
static void foo(const int something);
private:
A() = delete;
};
int main(){
A a{}; // whoops I just created an instance
}
但是,如果您将析构函数声明为已删除,则默认构造或聚合初始化都将不起作用 -- 它无法编译,因为编译器无法为 A
调用析构函数†
Demo
class A
{
public:
static bool foo(const char* filePath);
static void foo(const int something);
~A() = delete;
};
int main(){
A a{}; // fails
A b; // fails
}
由于您已经将析构函数声明为私有且未实现,因此所有其他内容都是多余的。 C++11 使它更容易,因为你不需要 private
,只需要在析构函数上使用 = delete
。明确声明析构函数为已删除是可取的,因为它向其他程序员传达了您从未打算实现它的信息。按照您的方式,某些程序员最初可能认为您只是忘记了包含实现。
您需要声明 默认构造函数 和 已删除的析构函数,以防止动态内存分配(通过 new
或 placement new),否则我们不会得到编译错误,因为现在我们可以调用 delete
或显式调用析构函数。如果我们方便地忘记了,那么一切都很好:
Demo
class A
{
public:
static bool foo(const char* filePath);
static void foo(const int something);
~A() = delete;
};
int main(){
A* a = new A(); // whoops I created an instance
// we leak memory
}
但是同时删除构造函数和析构函数可以防止这种情况发生:
Demo
class A
{
public:
static bool foo(const char* filePath);
static void foo(const int something);
~A() = delete;
A() = delete;
};
int main(){
A* a = new A(); // doesnt compile
A b{}; // doesn't compile
A c; // doesn't compile
}
†参考[class.dtor]:“如果可能调用的析构函数被删除或无法从调用。
我看到了 constructor = delete 的解释 here 但我想知道我是否也应该禁止析构函数调用。我正在尝试使用这样的 class:
class A
{
public:
static bool foo(const char* filePath);
static void foo(const int something);
private:
A() = delete;
~A();
};
我也应该写成~A() = delete;
吗?这有关系吗?
不,没关系。你也可以删除它,但是如果删除了构造函数,那么删除析构函数将不会做任何额外的事情。
第一个(已删除的构造函数)表明无法创建对象。第二个(已删除的析构函数)表示无法销毁对象。
请注意,可以使用各种 hack "create" 和初始化对象,但在那些情况下,所有的赌注都没有了,并且程序正在执行未定义的行为。
~A() = delete;
是多余的,因为你不能创建一个对象,所以没有必要担心析构函数。
事实上,对于您的代码,甚至不需要 A() = delete;
,因为所有 class 成员都是 static
。
正如 Luchian 在评论中正确提到的那样,这样的 class
最好声明为 namespace
。底层数据可以根据需要做成extern
/static
(注意:在C++20中,删除聚合的构造函数现在使得类型无法构造,因此不再有意外行为)
要在此处添加其他答案,您可能希望将析构函数声明为已删除而不是私有且未实现。这是因为,即使使用 private
删除的构造函数,您仍然可以使用 聚合初始化 来创建实例:
Demo
class A
{
public:
static bool foo(const char* filePath);
static void foo(const int something);
private:
A() = delete;
};
int main(){
A a{}; // whoops I just created an instance
}
但是,如果您将析构函数声明为已删除,则默认构造或聚合初始化都将不起作用 -- 它无法编译,因为编译器无法为 A
调用析构函数†
Demo
class A
{
public:
static bool foo(const char* filePath);
static void foo(const int something);
~A() = delete;
};
int main(){
A a{}; // fails
A b; // fails
}
由于您已经将析构函数声明为私有且未实现,因此所有其他内容都是多余的。 C++11 使它更容易,因为你不需要 private
,只需要在析构函数上使用 = delete
。明确声明析构函数为已删除是可取的,因为它向其他程序员传达了您从未打算实现它的信息。按照您的方式,某些程序员最初可能认为您只是忘记了包含实现。
您需要声明 默认构造函数 和 已删除的析构函数,以防止动态内存分配(通过 new
或 placement new),否则我们不会得到编译错误,因为现在我们可以调用 delete
或显式调用析构函数。如果我们方便地忘记了,那么一切都很好:
Demo
class A
{
public:
static bool foo(const char* filePath);
static void foo(const int something);
~A() = delete;
};
int main(){
A* a = new A(); // whoops I created an instance
// we leak memory
}
但是同时删除构造函数和析构函数可以防止这种情况发生:
Demo
class A
{
public:
static bool foo(const char* filePath);
static void foo(const int something);
~A() = delete;
A() = delete;
};
int main(){
A* a = new A(); // doesnt compile
A b{}; // doesn't compile
A c; // doesn't compile
}
†参考[class.dtor]:“如果可能调用的析构函数被删除或无法从调用。