三规则的例外情况?

Sam*_*man 16 c++ circular-dependency copy-constructor rule-of-three

我已经阅读了很多关于C++ 三规则的内容.很多人都发誓.但是当规则被陈述时,它几乎总是包括像"通常","可能"或"可能"这样的词,表示存在例外.我没有看到很多关于这些例外情况的讨论 - 三法则不成立的情况,或者至少在坚持它的情况下没有提供任何优势的情况.

我的问题是我的情况是否是三法则的合法例外.我相信在我下面描述的情况下,需要一个明确定义的复制构造函数和复制赋值运算符,但默认(隐式生成的)析构函数将正常工作.这是我的情况:

我有两个类,A和B.这里讨论的是A. B是A的朋友.A包含B对象.B包含一个A指针,用于指向拥有B对象的A对象.B使用此指针来操纵A对象的私有成员.除了A构造函数之外,B永远不会被实例化.像这样:

// A.h

#include "B.h"

class A
{
private:
    B b;
    int x;
public:
    friend class B;
    A( int i = 0 )
    : b( this ) {
        x = i;
    };
};
Run Code Online (Sandbox Code Playgroud)

和...

// B.h

#ifndef B_H // preprocessor escape to avoid infinite #include loop
#define B_H

class A; // forward declaration

class B
{
private:
    A * ap;
    int y;
public:
    B( A * a_ptr = 0 ) {
        ap = a_ptr;
        y = 1;
    };
    void init( A * a_ptr ) {
        ap = a_ptr;
    };
    void f();
    // this method has to be defined below
    // because members of A can't be accessed here
};

#include "A.h"

void B::f() {
    ap->x += y;
    y++;
}

#endif
Run Code Online (Sandbox Code Playgroud)

我为什么要这样设置我的课程?我保证,我有充分的理由.这些类实际上比我在这里包含的更多.

所以剩下的很容易,对吗?没有资源管理,没有三巨头,没问题.错误!A的默认(隐式)复制构造函数是不够的.如果我们这样做:

A a1;
A a2(a1);
Run Code Online (Sandbox Code Playgroud)

我们得到一个新的A对象a2,它a1意思a2.b是相同的a1.b,意思是a2.b.ap它仍然指向a1!这不是我们想要的.我们必须为A复制构造函数,它复制默认复制构造函数的功能,然后将new设置A::b.ap为指向新的A对象.我们将此代码添加到class A:

public:
    A( const A & other )
    {
        // first we duplicate the functionality of a default copy constructor
        x = other.x;
        b = other.b;
        // b.y has been copied over correctly
        // b.ap has been copied over and therefore points to 'other'
        b.init( this ); // this extra step is necessary
    };
Run Code Online (Sandbox Code Playgroud)

出于同样的原因,复制赋值运算符是必需的,并且将使用复制默认复制赋值运算符的功能然后调用的相同过程来实现b.init( this );.

但是没有必要使用明确的析构函数; 这种情况是三规则的例外.我对吗?

dsp*_*yer 9

不要太担心"三个规则".规则不是盲目服从的; 他们在那里让你思考.你曾经想过.而且你已经得出结论,析构函数不会这样做.所以不要写一个.该规则存在,以便您不要忘记编写析构函数,泄漏资源.

同样,这种设计为B :: ap创造了错误的可能性.这是一整类潜在的错误,如果它们是单个类,或者以更强大的方式捆绑在一起,可以消除.

  • 实际上我同意问题海报在这里采取的方法.那就是:如果有一个规则,每个人似乎都同意,并且你正在考虑打破它,不要只是思考,也*请求建议*.当你偏离公认的练习时,你冒着陷入被接受的习惯被制定以避免的陷阱的危险,所以不要犹豫丢弃许多人积累多年智慧的智慧. (3认同)