智能指针和不可复制的成员字段

Smart Pointers and non-copyable member fields

本文关键字:成员 字段 可复制 指针 智能      更新时间:2023-10-16

在阅读了大量关于类成员上下文中的(智能)指针的内容后,我仍然不确定如何处理后续情况。

我想创建Foo类型的对象,方法是调用实例化特定Bar对象的deafult构造函数,或者将某种指针传递给Foo的单参数构造函数。

  • 我不能使用unique_ptr,因为我仍然需要访问Foo之外的Bar对象
  • 如果我使用了原始指针,那么如果调用了Foo的deafult构造函数,我将需要调用delete,但如果调用了一个arg-ctr,则不需要调用delete
  • 然后是shared_ptr,但引用Herb Sutter的话:"不要将智能指针作为函数参数传递,除非你想使用或操纵智能指针本身,例如共享或转移所有权。"

那么,在下面的片段中(当然不编译),m_bar应该是什么类型?

struct Bar {
    Bar(int k) {} 
    Bar operator=(const Bar&) =delete;
    Bar (const Bar&) = delete;
};

struct Foo {
  Foo() : m_bar(5) {}
  Foo(Bar b) : m_bar(b); 
  Bar m_bar;
};
  • 我不能使用unique_ptr,因为我仍然需要访问Foo之外的Bar对象

unique_ptr不会阻止您访问Foo之外的对象。

如果你的意思是"我仍然需要在Foo对象的生命周期之外访问Bar对象",那么你的推理是合理的。在这种情况下,Foo不能成为对象的唯一所有者。

  • 如果我使用了原始指针,那么如果调用了Foo的deafult构造函数,我将需要调用delete,但如果调用了一个arg-ctr,则不需要调用delete

指针必须并且只能由其所有者删除。通过声明Foo必须删除指针,就意味着Foo拥有指针。

如果对象也可以由其他人拥有,那么设计似乎会导致共享所有权。

  • 然后是shared_ptr,但引用Herb Sutter的话:"不要将智能指针作为函数参数传递,除非您想使用或操纵智能指针本身,例如共享或转移所有权。"

根据描述,持股似乎正是你想要做的事情,Herb明确将其列为传递智能指针的合适情况之一。


现在,由于所有权是有条件的"在这里"或"在那里",所以共享指针并不是完全必要的。这只是最简单的解决方案,因此也是一个很好的解决方案。

对于您的情况,您可以想象maybe_unique_ptr。这样的智能指针在标准库中不存在。以下别名模板可能适用于您,但取决于提升:

template<class T>
using maybe_unique_ptr = boost::variant<std::unique_ptr<T>, T*>;
struct Foo {
    Foo()       : bar(std::make_unique<Bar>(5)) {}
    Foo(Bar* b) : bar(b) {}
    maybe_unique_ptr<Bar> bar;
};

当然,这意味着您必须使用boost::apply_visitor访问变体中的实例,这会使它更加麻烦。