标签: rule-of-zero

为什么析构函数会禁用隐式移动方法的生成?

我试着通过阅读这篇博客来了解零的规则.IMO,它说如果你声明自己的析构函数,那么不要忘记创建移动构造函数并将赋值移动为默认值.

示例:

class Widget {
public:
  ~Widget();         // temporary destructor
  ...                // no copy or move functions
};
Run Code Online (Sandbox Code Playgroud)

"添加析构函数会产生禁用生成移动函数的副作用,但由于Widget是可复制的,因此用于生成移动的所有代码现在都会生成副本.换句话说,向类中添加析构函数可能会导致 - 有效的动作可以用可能效率低下的副本无声地替换".

Scott Meyers的上述文字在引言中提出了一些问题:

  • 为什么声明析构函数会隐藏移动语义?
  • 声明/ definig析构函数只隐藏移动语义或复制构造函数和复制赋值以及隐藏移动语义吗?

c++ destructor move c++11 rule-of-zero

16
推荐指数
2
解决办法
2463
查看次数

"零规则"是否也适用于具有虚拟方法的类?

我发现Peter Sommerlads Slides(第32页)中提到的零法则非常引人注目.

虽然,我好像记得,有一个严格的规则,一个定义虚拟析构函数,如果类有虚拟成员和实际的.

struct Base {
    virtual void drawYourself();
    virtual ~Base() {}
};
struct Derived : public Base {
    virtual void drawYourself();
};
Run Code Online (Sandbox Code Playgroud)

析构函数的主体甚至可能是空的(它只需要vtbl中的条目).

我似乎记得在使用层次结构时

int main() {
    Base *obj = new Derived{};
    obj->drawYourself(); // virtual call to Derived::drawYourself()
    delete obj; // Derived::~Derived() _must_ be called
}
Run Code Online (Sandbox Code Playgroud)

那么delete obj 调用正确的析构函数是很重要的.这是正确的,如果我完全省略了析构函数定义,它就不会变成虚拟的,因此会调用错误的数字吗?

struct Base {
    virtual void drawYourself();
    // no virtual destructor!
}; …
Run Code Online (Sandbox Code Playgroud)

c++ destructor virtual-destructor c++11 rule-of-zero

9
推荐指数
1
解决办法
727
查看次数

零混乱规则?

所以我一直在阅读关于零规则的内容.

简化版:我不明白这条规则的目的.三和五的规则有点像"经验法则",但是我不能用这个规则看到"经验法则"或任何其他特定意图.

详细版本:

我来引述一下:

具有自定义析构函数,复制/移动构造函数或复制/移动赋值运算符的类应专门处理所有权.其他类不应该有自定义析构函数,复制/移动构造函数或复制/移动赋值运算符.

这是什么意思?什么是所有权,拥有什么?他们还展示了一个示例代码(我猜它与介绍有关):

class rule_of_zero
{
    std::string cppstring;
 public:
    rule_of_zero(const std::string& arg) : cppstring(arg) {}
};
Run Code Online (Sandbox Code Playgroud)

他们想要用什么表现出来,我真的迷失在这一点上.

此外,当您处理多态类并且析构函数被声明为public和virtual以及此块隐式移动的事实时,他们也在谈论场景.因此,您必须将它们全部声明为默认值:

class base_of_five_defaults
{
 public:
    base_of_five_defaults(const base_of_five_defaults&) = default;
    base_of_five_defaults(base_of_five_defaults&&) = default;
    base_of_five_defaults& operator=(const base_of_five_defaults&) = default;
    base_of_five_defaults& operator=(base_of_five_defaults&&) = default;
    virtual ~base_of_five_defaults() = default;
};
Run Code Online (Sandbox Code Playgroud)

这是否意味着每当你有一个带有析构函数的基类被声明为public和virtual时,你真的必须将所有其他特殊成员函数声明为默认值?如果是这样,我不明白为什么.

我知道这在一个地方很混乱.

c++ rule-of-zero

8
推荐指数
1
解决办法
1273
查看次数

unique_ptr,自定义删除和零规则

我正在编写一个使用C接口创建的两个对象的类.对象看起来像:

typedef struct... foo_t;
foo_t* create_foo(int, double, whatever );
void delete_foo(foo_t* );
Run Code Online (Sandbox Code Playgroud)

(同样如此bar_t).因为C++ 11,我想将它们包装在智能指针中,所以我不必编写任何特殊方法.该类将拥有这两个对象的唯一所有权,因此unique_ptr逻辑上有意义......但我仍然需要编写一个构造函数:

template <typename T>
using unique_ptr_deleter = std::unique_ptr<T, void(*)(T*)>;

struct MyClass {
     unique_ptr_deleter<foo_t> foo_;
     unique_ptr_deleter<bar_t> bar_;

     MyClass()
         : foo_{nullptr, delete_foo}
         , bar_{nullptr, delete_bar}
     { }

     ~MyClass() = default;

     void create(int x, double y, whatever z) {
         foo_.reset(create_foo(x, y, z));
         bar_.reset(create_bar(x, y, z));
};
Run Code Online (Sandbox Code Playgroud)

另一方面shared_ptr,我不必编写构造函数,或使用类型别名,因为我可以直接delete_foo进入reset()- 虽然这会使我的可MyClass复制,我不希望这样.

MyClass使用unique_ptr语义编写并仍然遵守Zero规则的正确方法是什么?

c++ c++11 rule-of-zero

7
推荐指数
1
解决办法
493
查看次数

C++ Zero of Zero:多态删除和unique_ptr行为

在最近实施零规则主题下的超载期刊中,作者描述了我们如何避免编写五个操作符规则,因为编写它们的原因是:

  1. 资源管理
  2. 多态删除

这两个都可以通过使用智能指针来处理.

在这里,我对第二部分特别感兴趣.

请考虑以下代码段:

class Base
{
public:
    virtual void Fun() = 0;
};


class Derived : public Base
{
public:

    ~Derived()
    {
        cout << "Derived::~Derived\n";
    }

    void Fun()
    {
        cout << "Derived::Fun\n";
    }
};


int main()
{
    shared_ptr<Base> pB = make_shared<Derived>();
    pB->Fun();
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,正如文章的作者解释的那样,我们通过使用共享指针获得多态删除,这确实有效.

但是,如果我shared_ptr用a 替换unique_ptr,我不再能够观察到多态删除.

现在我的问题是,为什么这两种行为有所不同?为什么不shared_ptr照顾多态删除unique_ptr

c++ polymorphism smart-pointers rule-of-zero

6
推荐指数
1
解决办法
2739
查看次数

理解零规则

我有一个基类,我不想让派生类可复制.为了使一切都明确,我以这种方式实现它:

class A {                                                                     
public:    
    A() = default;                                                                   
    virtual ~A() = default;                                                   
    A(const A&)  = delete;                                                    
    A(const A&&) = delete;                                                    
    A& operator=(const A&)  = delete;                                         
    A& operator=(const A&&) = delete;                                         

    virtual void vFun() = 0;                                                  
};                                                                            

class B : public A {                                                          
public:
    B() = default;                                                                       
    virtual ~B() = default;                                                   
    B(const B&)  = delete;                                                    
    B(const B&&) = delete;                                                    
    B& operator=(const B&)  = delete;                                         
    B& operator=(const B&&) = delete;                                         

    virtual void vFun() override {}                                           
};
Run Code Online (Sandbox Code Playgroud)

这是做这种事的正确方法吗?根据我的知识和我所读到的,答案是肯定的,但我想在将其引入生产系统之前确定.


编辑

总结一下:1)几乎总是不应删除运算符.那是因为"有无限的东西需要可动性".2)对于抽象基类,允许编译器生成特殊成员函数更安全,并且如果存在这种必要性,则将删除移动到派生类中.

c++ c++11 rule-of-zero

5
推荐指数
1
解决办法
653
查看次数

C ++零规则&什么是“用户声明的”构造函数?

在澄清Orbit的“ Lightness Races”之后,我缩小了职位范围。

看完这篇文章:零规则

我最了解了,但是我仍然想解决一些不清楚的问题:

1.看这句话:

如果类X的定义未明确声明move构造函数,则仅在以下情况下,将隐式声明为default:

X没有用户声明的副本构造函数,并且

X没有用户声明的副本分配运算符,

X没有用户声明的移动分配运算符,

X没有用户声明的析构函数,并且

move构造函数不会隐式定义为Delete。

是否应该全部5条语句共存(共享“和”关系)或仅其中一部分(共享“或”关系)?

2.用户声明的 ”复制构造函数\复制赋值运算符...是什么意思?

  • 是在.h文件中声明它(上述列表中的任何一个),但未实现用户声明的实现?

  • 是在.h文件中声明它(上面列表中的任何一个),并指定“ = deleted ”或“ = default ”视为用户声明的?

  • 是在.h文件中用空手镯{}声明它(上面的列表中的任何一个),并认为是用户声明的?

尊敬,

埃泰

c++ rule-of-zero

5
推荐指数
1
解决办法
370
查看次数

无法理解零规则中的C++ 11语法

我正在研究零度规则,并且对最终的一段代码有两个问题,这些代码证明了规则.

class module {
    public:
        explicit module(std::wstring const& name)
        : handle { ::LoadLibrary(name.c_str()), &::FreeLibrary } {}

        // other module related functions go here

    private:
        using module_handle = std::unique_ptr<void, decltype(&::FreeLibrary)>;

        module_handle handle;
    };
Run Code Online (Sandbox Code Playgroud)
  1. 为什么要使用大括号而不是括号来初始化句柄?
  2. 使用module_handle = std :: unique_ptr是什么用的; 在这种情况下是什么意思?是否可以用typedef替换它?

c++ idioms c++11 rule-of-zero

3
推荐指数
1
解决办法
928
查看次数

只是添加没有做任何事情的析构函数会导致编译错误(围绕std :: move),为什么?

在我学习的过程中std::move,我发现了一个奇怪的问题.

如果我只添加一个对完美程序无效的析构函数,我将收到编译错误.

#include <iostream>
using namespace std;

class M {
public:
  int database = 0;

  M &operator=(M &&other) {
    this->database = other.database;
    other.database = 0;
    return *this;
  }

  M(M &&other) { *this = std::move(other); }

  M(M &m) = default;
  M() = default;
  ~M() { /* free db */ }
};

class B {
public:
  M shouldMove;

  //~B(){}   //<---  ## Adding this line will cause compile error. ##
};

int main() {
  B b;
  B b2 = std::move(b); //## …
Run Code Online (Sandbox Code Playgroud)

c++ move-semantics c++11 rule-of-zero

3
推荐指数
1
解决办法
127
查看次数

零与基类析构函数的规则

我有一个基类Base和一个派生类D,我想为我自动生成移动构造函数和移动赋值运算符.遵循Zero规则,我将所有内存管理留给编译器,只使用level-2类(没有原始指针,数组等):

#include <iostream>

class Base{
  public:
    Base(): a_(42) {}
    virtual void show() { std::cout << "Base " << a_ << std::endl; }

  private:
    int a_;
};

class D : Base {
  public:
    D(): b_(666) {}
    void show() { std::cout << "D " << b_ << std::endl; }

  private:
    int b_;
};

int main() {
  Base b;
  b.show();
  D d;
  d.show();
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

这应该是吧,对吗?

输入C++核心指南:

基类析构函数应该是公共的和虚拟的,或者是受保护的和非虚拟的.

啊,所以我想我必须添加一个析构函数Base.但这将取消自动生成的移动功能!

什么是干净的出路?

c++ c++11 rule-of-zero

3
推荐指数
1
解决办法
336
查看次数

如何对包含带有字符串的自定义对象向量的类正确地应用5(或零?)规则

我在围绕所有权问题以及通过移动最大化性能方面遇到麻烦。想象一下这套模拟Excel工作簿的类的假设。

namespace Excel {

class Cell
{
public:
  // ctors
  Cell() = default;
  Cell(std::string val) : m_val(val) {};
  // because I have a custom constructor, I assume I need to also
  // define copy constructors, move constructors, and a destructor.
  // If I don't my understanding is that the private string member 
  // will always be copied instead of moved when Cell is replicated 
  // (due to expansion of any vector in which it is stored)? Or will 
  // it …
Run Code Online (Sandbox Code Playgroud)

c++ move c++11 rule-of-zero

1
推荐指数
1
解决办法
60
查看次数