7

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

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

  • 取得所有权
  • 不要拥有所有权
  • 分享

关于返回值:

  • 发布(“按值返回”在此组中)
  • 不要释放
  • 分享

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

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

此类指南可能会使用诸如 unique_ptr、shared_ptr 等标准结构。如果没有此类指南,那么也欢迎可能存在语法误解的示例。

4

3 回答 3

9

我不明白为什么使用智能指针是不够的。我想不出任何其他我不会归类为代码气味的东西。在原始指针上使用智能指针可以使所有权和响应能力非常清晰:

  • 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++ pre-11,您将不得不求助于boost::shared_ptrboost:weak_ptr.

于 2011-11-03T10:45:29.403 回答
0

如果我理解你,那么 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_typereference_typereturn_type表明其含义。

于 2011-11-03T10:21:50.650 回答
0

我只是在需要时将这种语法用于参数:

示例构造函数声明:

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

在呼叫站点使用:

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

Wheret_ownership_policy::t_take只是一个虚拟的重载消歧器类型名。

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

对于“返回”:

void func(t_container<t_type>& outValue);

t_container您选择的指针容器类型在哪里。然后容器类型已经实现了必要的样板。该容器可能类似于shared_ptr,或您编写的某些专业化。

对于更复杂的类型,我会经常使用如下语法:

void func(t_special_container& outValue) {
  ...
  outValue.take(ptr);
  - or -
  outValue.copy(ptr);
于 2011-11-03T09:51:40.030 回答