C++强制使用unique_ptr进行动态分配

C++ force dynamic allocation with unique_ptr?

本文关键字:ptr 动态分配 unique C++      更新时间:2023-10-16

我发现unique_ptr可以指向已经存在的对象。例如,我可以这样做:

class Foo {
public:
  Foo(int nb) : nb_(nb) {}
private:
  int nb_;
};
int main() {
  Foo f1(2);
  Foo* ptr1(&f1);
  unique_ptr<Foo> s_ptr1(&f1);
  return 0;
}

我的问题是:

如果我创建一个类unique_ptr作为数据成员(其中 Bar 是删除复制构造函数的类)和一个将指针作为参数的构造函数,我可以防止用户将已经存在的对象/变量作为参数传递(在该构造函数中)(即强制他使用 new 关键字)?因为如果他这样做,我将无法保证我的类对象的有效状态(用户仍然可以从类外部使用他们的地址修改数据成员)。并且我无法将 Bar 的内容复制到另一个内存区域。

例:

class Bar {
public:
  Bar(/* arguments */) { /* data members allocation */ }
  Bar(Bar const& b) = delete;
  /* Other member functions */
private:
  /* data members */
};
class Bar_Ptr {
public:
  Bar_Ptr(Bar* ptr) {
    if (ptr != nullptr) { ptr_ = unique_ptr<Bar> (ptr); }
  } /* The user can still pass the address of an already existing Bar ... */
  /* Other member functions */
private:
  unique_ptr<Bar> ptr_;
};

你不能阻止程序员做愚蠢的事情。std::unique_ptrstd::shared_ptr都包含使用现有 ptr 创建实例的选项。我什至见过传递自定义删除程序以防止删除的情况。(对于这些情况,共享 ptr 更优雅)

因此,如果您有指针,则必须知道它的所有权。这就是为什么我更喜欢使用std::unique_ptrstd::shared_ptrstd::weak_ptr作为"拥有"指针,而原始指针表示非拥有指针。如果将其传播到创建对象的位置,则大多数静态分析器可以告诉您犯了错误。

因此,我会将类Bar_ptr重写为如下所示的内容:

class Bar_ptr {
public:
    explicit Bar_ptr(std::unique_ptr<Bar> &&bar)
        : ptr(std::move(bar)) {}
    // ...
}

这样,类的 API 将强制执行所有权转移,并且由调用方提供有效的unique_ptr。换句话说,您不必担心传递未分配的指针。

没有人阻止呼叫者写:

Bar bar{};
Bar_ptr barPtr{std::unique_ptr<Bar>{&bar}};

虽然如果你有一个像样的静态分析器,甚至只是一个代码审查,我希望这段代码被拒绝。

不,你不能。你不能阻止人们做愚蠢的事情。声明一个基于模板化参数返回新对象的模板化函数。

我以前见过类似的东西。诀窍是你创建一个函数(我们称之为make_unique),它接受对象(不是指针,对象,所以也许使用隐式构造函数,它可以"接受"类构造函数参数),这个函数将创建并返回unique_ptr。像这样:

template <class T> std::unique_ptr<T> make_unique(T b);

顺便说一句,你可以推荐人们使用这个功能,但没有人会强迫他们做你推荐的事情......

你不能阻止人们做错事。但你可以鼓励他们做正确的事。或者至少,如果他们做错了事,那就让它更明显。

例如,对于 Bar ,不要让构造函数采用裸指针。按值或按&&unique_ptr 秒。这样,您可以强制调用方创建这些unique_ptr。您只需将它们移动到成员变量中即可。

这样,如果调用方

做了错误的事情,错误就出在调用方的代码中,而不是你的代码中。