如何安全地将new创建的对象传递给构造函数

Rom*_*hev 2 c++ pointers memory-management class-design c++11

我有几个类看起来像这样:

struct equation {};

struct number: equation {
    number(int n): value(n) {}

  private:
    int value;
};

struct operation: equation {
    operation(const equation* left, const equation* right)
        : left(left), right(right) {}

  private:
    std::unique_ptr<equation> left, right;
};
Run Code Online (Sandbox Code Playgroud)

它们的设计方式operation取决于传递给构造函数的指针的所有权.

我的问题是如何修改此类以便能够以下一种方式安全地使用它:

operation op(new number(123), new number(456));
Run Code Online (Sandbox Code Playgroud)

在我看来,如果创建第一个对象而第二个不是(比如从number构造函数抛出异常)那么它就是内存泄漏 - 没有人会删除指向第一个数字的指针.

这种情况怎么办?我不想按顺序分配对象,如果出现故障则删除它们 - 它太冗长了.

son*_*yao 10

我不想按顺序分配对象,如果出现故障则删除它们 - 它太冗长了.

是.你只需要更彻底地应用智能指针习语; 更确切地说,将参数类型更改为std::unique_ptr,并使用std::make_unique (自C++ 14)(而不是new显式使用)以避免此问题.例如

struct operation: equation {
    operation(std::unique_ptr<equation> left, std::unique_ptr<equation> right)
        : left(std::move(left)), right(std::move(right)) {}

  private:
    std::unique_ptr<equation> left, right;
};
Run Code Online (Sandbox Code Playgroud)

然后

operation op(std::make_unique<number>(123), std::make_unique<number>(456));
Run Code Online (Sandbox Code Playgroud)

注意在std::make_unique这里使用很重要,里面创建的原始指针std::make_unique保证由返回的管理std::unique_ptr; 即使是第二次std::make_unique失败 std::unique_ptr,第一次创建std::make_unique也会看到它所拥有的指针被破坏了.对于std::make_unique首先调用第二个的情况也是如此.

在C++ 14之前,您可以制作自己的版本std::make_unique; 基本的一个很容易写.是一个可能的实现.

// note: this implementation does not disable this overload for array types
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
Run Code Online (Sandbox Code Playgroud)

  • ...因为现在每个分配和构造都在make_unique中"原子地"发生. (2认同)
  • @RomanGolyshev很容易制作自己的版本.请参阅答案中链接的参考. (2认同)