繁体   English   中英

C ++:实现复制构造函数和复制赋值运算符

[英]C++ : Implementing copy constructor and copy assignment operator

在阅读了C ++中的复制构造函数和复制赋值运算符之后,我尝试创建一个简单的例子。 虽然下面的代码片段显然有效,但我不确定我是否正确地实现了复制构造函数和复制赋值运算符。 能不能指出是否有任何错误/改进或更好的例子来理解相关概念。

class Foobase
{
    int bInt;

public:
    Foobase() {}

    Foobase(int b) { bInt = b;}

    int GetValue() { return bInt;}

    int SetValue(const int& val) { bInt = val; }
};


class Foobar
{
    int var;    
    Foobase *base;      

public:
    Foobar(){}

    Foobar(int v)
    {
        var = v;        
        base = new Foobase(v * -1);

    }

    //Copy constructor
    Foobar(const Foobar& foo)
    {       
        var = foo.var;
        base = new Foobase(foo.GetBaseValue());
    }

    //Copy assignemnt operator
    Foobar& operator= (const Foobar& other)
    {
        if (this != &other) // prevent self-assignment
        {
            var = other.var;
            base = new Foobase(other.GetBaseValue());

        }
        return *this;
    }

    ~Foobar()
    {
        delete base;
    }

    void SetValue(int val)
    {
        var = val;
    }

    void SetBaseValue(const int& val)
    {
        base->SetValue(val);
    }

    int GetBaseValue() const
    {
        return(base->GetValue());
    }

    void Print()
    {
        cout<<"Foobar Value: "<<var<<endl;
        cout<<"Foobase Value: "<<base->GetValue()<<endl;

    }   

};

int main()
{
    Foobar f(10);       
    Foobar g(f);  //calls copy constructor
    Foobar h = f; //calls copy constructor

    Foobar i;
    i = f;

    f.SetBaseValue(12);
    f.SetValue(2);    

    Foobar j = f = z; //copy constructor for j but assignment operator for f

    z.SetBaseValue(777);
    z.SetValue(77);

    return 1;
}

您的副本分配运算符未正确实现。 被分配的对象泄漏其base指向的对象。

你的默认构造函数也是不正确的:它使basevar都没有初始化,因此当你调用delete base;时,无法知道是否有效以及在析构函数中delete base; ,糟糕的事情发生。

实现复制构造函数和复制赋值运算符以及知道您已正确完成的最简单方法是使用复制和交换习惯用法

只有Foobar需要自定义复制构造函数,赋值运算符和析构函数。 Foobase不需要一个,因为编译器提供的默认行为足够好。

Foobar的情况下,您在赋值运算符中有泄漏。 您可以通过在分配对象之前释放对象来轻松修复它,这应该足够好了。 但是如果你曾经向Foobar添加第二个指针成员,那么当事情变得复杂时你就会看到它。 现在,如果在分配第二个指针时遇到异常,则需要正确清理分配的第一个指针,以避免损坏或泄漏。 当你添加更多的指针成员时,事情变得比多项式更复杂。

相反,您要做的是根据复制构造函数实现赋值运算符。 然后,您应该根据非抛出交换函数实现复制构造函数。 阅读有关复制和交换习语的详细信息。

此外, Foobar的默认构造函数不会默认初始化成员。 这很糟糕,因为它不是用户期望的。 成员指针指向任意地址,int具有任意值。 现在,如果您使用构造函数创建的对象,则非常接近Undefined Behavior Land。

我有一个非常简单的补丁:

class Foobar
{
  int var;    
  std::unique_ptr<FooBase> base;

...

这应该让你开始。

底线是:

  1. 不要在代码中调用delete (专家见第2点)
  2. 不要在你的代码中调用delete (你知道的更好......)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM