【问题标题】:Calling dynamically allocated class' copy constructor inside a copy constructor?在复制构造函数中调用动态分配的类的复制构造函数?
【发布时间】:2013-03-06 07:30:28
【问题描述】:

假设构造函数、析构函数和赋值运算符写得正确,为什么我不能像这样实现复制构造函数:

MyClass::MyClass(const MyClass &other)
{
    this->value = new Value(*(other.value));
}

我看到的大多数示例都是这样做的:(因为它们通常处理数组)

MyClass::MyClass(const MyClass &other)
{
    Value *temp = new Value;
    *temp = *(other.value);
    this->value = temp;
}

但在第一个示例中,如果“new”抛出,“other”不受影响,并且如果 Value 的复制构造函数抛出,“new”不会在传播异常之前释放分配的内存吗?

由于这是一个迷你智能指针本身,我特别避免使用 std::unique_ptr 和其他智能指针。

【问题讨论】:

  • 为什么value首先是动态分配的?您试图以高昂的成本为其赋予价值语义,并且做错了吗?
  • Value 是指向另一个类的指针。也许“价值”这个名字是错误的词——我应该使用更通用的“数据”或“其他类”。如果我是“也做错了”,这就是我问这个问题的原因,因为我不知道我做对了还是错。
  • @JaminGrey 如您所示,实现复制构造函数没有任何问题。如果复制构造函数抛出,the memory allocated by new will be freed before the exception propagates。事实上,如果 Value 的赋值运算符抛出异常,第二个示例可能会导致内存泄漏。
  • @WhozCraig 不是被“新”清理了吗?这就是link Praetorian 发布的暗示,以及@bames53's answer 所说的,除非我误读了一些东西,我可能是。 new 不会捕获构造函数中抛出的异常或复制正在分配的类的构造函数吗?
  • @JaminGrey 是的,你是完全正确的,我不得不通过帖子和一些标准参考来确定,但他(Paretorian)和你是完全正确的;这就是它应该表现的方式,因此我坚定地站在选项 #1 =P 的阵营中

标签: c++ copy-constructor


【解决方案1】:

如果 Value 的复制构造函数抛出异常,在传播异常之前不会“新建”释放分配的内存吗?

是的。

没有特别的理由不使用单行方法而不是三行赋值版本。


由于您正在编写智能指针,因此以下内容不适用,但在普通类中,您可能会将手动指针管理包装为 RAII 类型。看起来 std::unique_ptr 具有您想要的语义,而 make_unique 帮助器使它变得非常简单:

#include <memory>

// probably will be added to the standard
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args &&... args) {
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

class Value {};

class MyClass {
    std::unique_ptr<Value> value;

public:
    MyClass() : value{make_unique<Value>()} {}

    MyClass(MyClass const &other) : value{make_unique<Value>(*other.value)} {}

    MyClass &operator= (MyClass const &other) {
        value = make_unique<Value>(*other.value);
        return *this;
    }
    // you can also implement assignment from rvalue ref as an optimization
};

【讨论】:

  • 是的,因为 'other' 是 const,所以我说它不会受到影响——那部分不是问题,而是陈述。 =)也感谢您回答实际问题!我确实已经有一个 make_unique 助手,并且在我的代码中通常使用 std::unique_ptr 和 std::shared_ptr,我应该提到我专门为这个特定的类避免它。哎呀。
【解决方案2】:

问题太多了,无法一一列举。我建议你学习三法则:

就像我说的,这里的正确解决方案可能是

struct MyClass
{
     MyClass(const MyClass &other) : value(other.value) {}

    private:
     OtherClass value;
};

如果value 是某种必须存在于堆上的资源,那么它将被声明为

struct MyClass
{
    // ...
    private:
       std::unique_ptr<OtherClass> value;
};

这样你就不会(嗯,很容易)在所有权语义和内存管理上出错。

【讨论】:

  • 我在问一个我不理解的关于三规则的一部分的问题。我在原始问题中提到了这一点。提供 std::unique_ptr 是一个很好的建议!但在这种情况下,我特别避免使用它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-08-07
  • 2012-02-28
  • 2013-06-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-13
相关资源
最近更新 更多