c++ - 使用作为参数返回的指针的最佳实践是什么

标签 c++ std

通常,当创建指向对象的指针并从函数返回时,您使用 unique_ptr 使用它以确保它在作用域结束时被删除。

CustomType* GetTheObject(); // Let's say this the function signature and it returns a new object

void Main() {
   auto object = make_unique(GetTheObject());
   object->DoSomething();
   // Then the object is deleted automatically
}

如果函数签名是这样的怎么办
bool GetTheObject(CustomType** object);

我可以想象一种相当冗长的消费方式
void Main() {
   // Declare a pointer which we never need
   CustomType* object_ptr;
   if(GetTheObject(&object_ptr)) {
      // Then create a unique_ptr out of it
      auto object = make_unique(object_ptr);
      object->DoSomething();
      // Then the object is deleted automatically
   }
}

在这种情况下,是否有更好的推荐方式来使用对象。我可以考虑另一个实现 & 运算符的 unique_ptr2 类,然后像这样使用它
unique_ptr2 object;
if(GetTheObject(&object)) {
   // use it
}

是否有一个可以使用的 unique_ptr2 实现来允许这样做?感觉还是不太理想。有没有更好的办法?

最佳答案

我可能很想编写代码来自动与唯一 ptr 进行转换。我们从现有函数“自动”生成一个具有相同签名的新函数,但是 T*返回值为 unique_ptr<T>T**参数是 unique_ptr<T>*论据。

然后我们使用 RAII 和模板元编程注入(inject)转换样板。

一个 ptr_filler是一种 RAII 类型,可以转换 unique_ptr<T>*变成 T** :

template<class T>
struct ptr_filler {
  std::unique_ptr<T>* output = nullptr;
  T* temporary = nullptr;
  ptr_filler( std::unique_ptr<T>* bind ):output(bind) {}
  operator T**()&&{return &temporary;}
  ~ptr_filler() {
    if (temporary)
      *output = std::unique_ptr<T>(temporary);
  }
};
ret_converter_t执行从 C 风格 API 到 C++ unique-ptr API 的类型转换:
template<class T> struct ret_converter { using type=T; };
template<class T> using ret_converter_t = typename ret_converter<T>::type;
template<class T> struct ret_converter<T*> { using type=std::unique_ptr<T>; };
get_converter_t将 C 风格 API 的参数类型转换为通过 ptr_filler 填充唯一 ptrs 的类型:
template<class T> struct get_converter { using type=T; };
template<class T> using get_converter_t = typename get_converter<T>::type;
template<class T> struct get_converter<T**> { using type=ptr_filler<T>; };

最后,call从您传递给它的函数指针中推断出它的参数,然后将参数和 retval 转换为使用唯一的 ptr 内存管理,并调用函数 f为你:
template<class R, class...Args>
ret_converter_t<R> call( R(* f)(Args...), get_converter_t<Args>... args ) {
  return static_cast<ret_converter_t<R>>( f( std::forward<decltype(args)>(args)... ) );
}

现在我们可以:
struct CustomType {
  int x;
};
CustomType* GetTheObject(int x) { return new CustomType{x}; }
bool MakeTheObject( CustomType** pp, int a, int b ) { *pp = new CustomType{a+b}; return a>b; }

我们能做的:
int main() {
  std::unique_ptr<CustomType> ptr;
  std::cout << call( MakeTheObject, &ptr, 2, 1 ) << " = 1\n";
  std::cout << ptr->x << " = 3\n";
  ptr = call( GetTheObject, 7 );
  std::cout << ptr->x << " = 7\n";
}

您可以通过 call<MakeTheObject> 获得更高级的体验语法,但它需要工作。这假定您要包装的 API 是 C-ish API,但返回 new 'd 对象。

Live example .

关于c++ - 使用作为参数返回的指针的最佳实践是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59291552/

相关文章:

c++ - 使用 std::pair 类的头文件中的 typedef 错误

c# - 开发人员笔记本配置

c++ - 已经 "EOF"ed ifstream 上的 peek() 是否继续返回 EOF?

c++ - 在 C++ 中检索 std::map 的随机键元素

c++ - 如何在 C++ 中迭代字符串和结构的映射?

c++ - 为什么 operator== 不足以满足 std::unordered_map 的要求? - C++

c++ - 仅在条件适用时排序 - std::sort

c++ - 寻路算法创建循环

c++ - 使用指针参数调用函数与引用参数

c++ - 这与 ObjectWrap::Unwrap 的 Holder