首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么在声明析构函数时必须声明“复制和移动构造函数”?

为什么在声明析构函数时必须声明“复制和移动构造函数”?
EN

Stack Overflow用户
提问于 2018-01-24 12:33:20
回答 3查看 8.2K关注 0票数 13

我有一个NonCopyable类和一个从NonCopyable派生的Application

代码语言:javascript
复制
class NonCopyable
{
public:
    NonCopyable() = default;
    virtual ~NonCopyable() = default;
    NonCopyable(NonCopyable const&) = delete;
    NonCopyable& operator =(NonCopyable const&) = delete;
    NonCopyable(NonCopyable&&) = delete;
    NonCopyable& operator=(NonCopyable&&) = delete;
};

class Application : public NonCopyable
{
public:
    ~Application() { /* ...delete stuff... */ }
};

正如您所看到的,我不需要重新声明已删除的移动构造函数或赋值操作符,因为我已经在基类中声明了它们。但是为什么Resharper建议我宣布其他特殊的成员功能呢?它说:

Application定义非默认析构函数,但不定义副本构造函数、副本赋值操作符、移动构造函数或移动赋值操作符hicpp-特殊成员函数。 还有cppcoreguidelines-特殊成员函数--具有相同信息的提醒。

当前的解决办法是显式地编写所有这些代码,以消除警告:

代码语言:javascript
复制
class Application : public NonCopyable
{
public:
    ~Application() { /* ...delete stuff... */ }
    Application(Application const&) = delete;
    Application& operator =(Application const&) = delete;
    Application(Application&&) = delete;
    Application& operator=(Application&&) = delete;
};
EN

回答 3

Stack Overflow用户

发布于 2018-01-24 13:47:44

通常情况下,如果一个类定义了一个与编译器自动生成的不同的析构函数,那么它的目的就是释放一些由类管理的资源。

如果析构函数必须释放某些资源,那么通常还需要用户定义的构造函数来初始化该资源,用户定义的复制构造函数用于创建同一类型的现有对象所拥有的资源的副本,以及用户定义的移动构造函数从停止存在的临时对象中获得资源的所有权。

类似地,还需要一个复制赋值运算符和移动赋值运算符,以便像a = b这样的表达式可以将资源复制或移动到现有对象。

如果类没有一个或多个这些构造函数或赋值操作符,那么实际上,使用多个对象的代码通常不会一致运行(例如,一个析构函数释放资源两次,因为它由两个对象共享,导致未定义的行为,等等)。

当然,在某些情况下,类不需要完整的构造函数、赋值操作符和析构函数。但是,忽略其中一个通常是程序员的错误(与预期的效果不同),因此代码分析工具经常会抱怨这种情况。

票数 5
EN

Stack Overflow用户

发布于 2018-01-24 13:18:44

默认情况下,删除不继承

假设存在某种传递性是错误的(在构造对象时,我总是需要使用具有类似签名的超类构造函数)。

下面是一个反例:

代码语言:javascript
复制
#include <string>
#include <iostream>

class NonCopyable
{
public:
    NonCopyable() = default; // Added this little fella
    virtual ~NonCopyable() = default;
    NonCopyable(const NonCopyable &) = delete;
    NonCopyable& operator =(NonCopyable const&) = delete;
    NonCopyable(NonCopyable&&) = delete;
    NonCopyable& operator=(NonCopyable&&) = delete;
};

class Application : public NonCopyable
{
public:
    Application() = default;
    Application(const Application& a) : NonCopyable(), x(a.x){}
    ~Application() { /* ...delete stuff... */ }
    std::string x;
};

int main(){
   Application a;
   a.x = "Hello";
   Application b(a);

   std::cout << b.x << std::endl;

}

如您所见,通过使用超类的唯一可用构造函数,我完全能够声明子类的复制构造函数。我也可以声明规则5的其他构造函数,这就是为什么静态分析器对规则5发出警告的原因。

结论: NonCopyable是一个无用的类。

票数 4
EN

Stack Overflow用户

发布于 2018-01-24 12:46:33

所有ReSharper都知道,您定义了一个非平凡的析构函数,并且没有遵循3/5规则的其余部分。是的,由于复制/移动构造函数在基类中被删除,所以默认情况下会删除它们,但是ReSharper如何知道这是理想的行为?因此,警告您是有意义的,除非您显式地将它们标记为delete

您可以在本地禁用警告,如您建议的那样,可以使用杂注或显式delete构造函数/赋值。

作为解决办法,您可以引入虚拟cleanup()方法,从NonCopyable析构函数调用它,并在派生类中重写它(而不是析构函数)。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48422601

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档