C++ 强制使用 unique_ptr 进行动态分配?
C++ force dynamic allocation with unique_ptr?
我发现 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 创建一个 class 作为数据成员(其中 Bar一个 class 复制构造函数被删除的地方)和一个将指针作为参数的构造函数,我可以阻止用户传递一个已经存在的 object/variable 作为参数(在那个构造函数中)(即强迫他使用 new 关键字)?
因为如果他这样做,我将无法保证我的 class 对象的有效状态(用户仍然可以使用 class 之外的地址修改数据成员)..我可以't将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_;
};
不,你不能。你不能阻止人们做愚蠢的事情。声明一个模板化函数,returns 一个基于模板化参数的新对象。
我以前见过类似的东西。
诀窍是你创建一个函数(让我们称之为make_unique
)接受对象(不是指针,对象,所以可能使用隐式构造函数,它可以"take" class构造函数参数),此函数将创建 return 和 unique_ptr
。像这样:
template <class T> std::unique_ptr<T> make_unique(T b);
顺便说一句,你可以推荐别人使用这个功能,但是没有人会强迫他们按照你的推荐去做...
你无法阻止人们做错事。但是你可以鼓励他们做正确的事。或者至少,如果他们做错了事,让它更明显。
例如,使用Bar
,不要让构造函数采用裸指针。让它花费 unique_ptr
s,按值或按 &&
。这样,您就可以强制 caller 创建那些 unique_ptr
。您只是将它们移动到您的成员变量中。
那样的话,如果调用者做错了事,错误就在调用者的代码中,而不是你的。
你不能阻止程序员做傻事。 std::unique_ptr
和 std::shared_ptr
都包含使用现有 ptr 创建实例的选项。我什至见过传递自定义删除器以防止删除的情况。 (对于这些情况,共享 ptr 更优雅)
所以如果你有一个指针,你必须知道它的所有权。这就是为什么我更喜欢使用 std::unique_ptr
、std::shared_ptr
和 std::weak_ptr
作为 'owning' 指针,而原始指针表示非拥有指针。如果您将此传播到创建对象的位置,大多数静态分析器会告诉您您犯了一个错误。
因此,我会将 class Bar_ptr 重写为:
class Bar_ptr {
public:
explicit Bar_ptr(std::unique_ptr<Bar> &&bar)
: ptr(std::move(bar)) {}
// ...
}
由此,您的 class 的 API 强制执行所有权转移,并且由调用者提供有效的 unique_ptr。换句话说,您不必担心传递未分配的指针。
没有人阻止来电者写:
Bar bar{};
Bar_ptr barPtr{std::unique_ptr<Bar>{&bar}};
尽管如果你有一个像样的静态分析器或者甚至只是一个代码审查,我希望这个代码不会被拒绝。
我发现 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
示例:
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_;
};
不,你不能。你不能阻止人们做愚蠢的事情。声明一个模板化函数,returns 一个基于模板化参数的新对象。
我以前见过类似的东西。
诀窍是你创建一个函数(让我们称之为make_unique
)接受对象(不是指针,对象,所以可能使用隐式构造函数,它可以"take" class构造函数参数),此函数将创建 return 和 unique_ptr
。像这样:
template <class T> std::unique_ptr<T> make_unique(T b);
顺便说一句,你可以推荐别人使用这个功能,但是没有人会强迫他们按照你的推荐去做...
你无法阻止人们做错事。但是你可以鼓励他们做正确的事。或者至少,如果他们做错了事,让它更明显。
例如,使用Bar
,不要让构造函数采用裸指针。让它花费 unique_ptr
s,按值或按 &&
。这样,您就可以强制 caller 创建那些 unique_ptr
。您只是将它们移动到您的成员变量中。
那样的话,如果调用者做错了事,错误就在调用者的代码中,而不是你的。
你不能阻止程序员做傻事。 std::unique_ptr
和 std::shared_ptr
都包含使用现有 ptr 创建实例的选项。我什至见过传递自定义删除器以防止删除的情况。 (对于这些情况,共享 ptr 更优雅)
所以如果你有一个指针,你必须知道它的所有权。这就是为什么我更喜欢使用 std::unique_ptr
、std::shared_ptr
和 std::weak_ptr
作为 'owning' 指针,而原始指针表示非拥有指针。如果您将此传播到创建对象的位置,大多数静态分析器会告诉您您犯了一个错误。
因此,我会将 class Bar_ptr 重写为:
class Bar_ptr {
public:
explicit Bar_ptr(std::unique_ptr<Bar> &&bar)
: ptr(std::move(bar)) {}
// ...
}
由此,您的 class 的 API 强制执行所有权转移,并且由调用者提供有效的 unique_ptr。换句话说,您不必担心传递未分配的指针。
没有人阻止来电者写:
Bar bar{};
Bar_ptr barPtr{std::unique_ptr<Bar>{&bar}};
尽管如果你有一个像样的静态分析器或者甚至只是一个代码审查,我希望这个代码不会被拒绝。