c++中获取所有权和释放对象的语法指南

Syntax guidelines for taking ownership and releasing objects in C++

本文关键字:语法 对象 释放 获取 所有权 c++      更新时间:2023-10-16

我想知道-是否有任何关于c++(非)成员函数的语法指南,使我能够理解(如果可能的话,没有注释)其参数和返回值的所有权策略。我所说的所有权是指所有者对其拥有的对象的销毁负责。

我区分以下关于参数的规则:

  • 不占有所有权

和关于返回值:

  • release ('return by value'在该组中)
  • 不要发布

例如,通过引用传递对象并不获取它的所有权:

void func(object & obj) { ... }

这样的指南可以使用unique_ptr、shared_ptr等标准结构。如果没有这样的指导方针,那么也欢迎提供可能的语法误解示例。

我不明白为什么使用智能指针不够。我想不出还有什么东西不属于代码气味。使用智能指针而不是原始指针使所有权和责任非常清晰:

  • auto_ptr/unique_ptr -单一所有者,所有权转移
  • shared_ptr -多个所有者,所有权可能转移
  • scoped_ptr -单一所有者,所有权不能转让
  • weak_ptr -观察者(但shared_ptr可以从weak_ptr创建)

我认为这些足以清楚地表明责任,例如

void func(std::auto_ptr<Class> input) {...} // func() takes ownership of input
void func(std::shared_ptr<Class> input) {...} // func() and caller share ownership
std::auto_ptr<Class> func() {...} // caller takes ownership of returned value
std::shared_ptr<Class> func() {...} // func() and caller shares ownership of returned object
std::weak_ptr<Class> func() {...} // func() owns created object, but caller may observe it

正如你所提到的,参考文献在这个意义上也是很好的。注意,如果需要使用一些自定义机制来释放指针,shared_ptrunique_ptr支持自定义删除器。auto_ptr没有此功能。

注意!如果您使用的是c++ 11之前版本,则必须使用boost::shared_ptrboost:weak_ptr

如果我理解你,那么Boost call_traits可能是你正在寻找的:

示例(从文档中复制):

template <class T>
struct contained
{
   // define our typedefs first, arrays are stored by value
   // so value_type is not the same as result_type:
   typedef typename boost::call_traits<T>::param_type       param_type;
   typedef typename boost::call_traits<T>::reference        reference;
   typedef typename boost::call_traits<T>::const_reference  const_reference;
   typedef T                                                value_type;
   typedef typename boost::call_traits<T>::value_type       result_type;
   // stored value:
   value_type v_;
   // constructors:
   contained() {}
   contained(param_type p) : v_(p){}
   // return byval:
   result_type value() { return v_; }
   // return by_ref:
   reference get() { return v_; }
   const_reference const_get()const { return v_; }
   // pass value:
   void call(param_type p){}
};

并不比param_type, reference_typereturn_type更清楚地表明意思

我只是在需要的地方对参数使用这种语法:

示例构造函数声明:

t_array(const t_ownership_policy::t_take& policy, THESpecialType* const arg);

在呼叫站点使用:

t_array array(t_ownership_policy::Take, THESpecialTypeCreate(...));

其中t_ownership_policy::t_take只是一个虚拟的重载消歧器typename。

在这个系统中,有多个策略,每个策略都有单独的类型。我喜欢每个策略唯一的类型,因为类型化枚举(例如)不容易支持初始化,而且很容易将不受支持的策略传递给函数或构造函数。"多态"策略可以减少符号计数,但这是一个痛苦,因为它将错误检测推到运行时。

为"返回":

void func(t_container<t_type>& outValue);

其中t_container为您选择的指针容器类型。那么容器类型已经实现了必要的样板。这个容器可以是shared_ptr之类的东西,或者是您编写的某种专门化。

对于更复杂的类型,我经常使用这样的语法:

void func(t_special_container& outValue) {
  ...
  outValue.take(ptr);
  - or -
  outValue.copy(ptr);