如何在 C++11 中 return 包含自定义删除器的 std::unique_ptr?

How to return the std::unique_ptr containing custom deleter in C++11?

我的应用程序编译器最多只能支持 c++11

下面是我的项目和函数 get_conn() returns std::unique_ptr 的代码片段,带有自定义删除器(删除器需要两个参数)。我正在为 return 类型使用 auto 关键字,但它给出了一个错误,就像 if is compiled with c++11 (compiles fine with c++14)

error: ‘get_conn’ function uses ‘auto’ type specifier without trailing return type

演示示例代码:

#include <iostream>
#include <functional>
#include <memory>
using namespace std;


// Dummy definition of API calls                                                                                                             
int* open_conn (int handle)
{
  return new int;
}
void close_conn (int handle, int *conn)
{}

auto get_conn (int handle)
{
  // API call                                                                                                                                
  int* conn = open_conn (handle);    
  auto delete_conn = [](int *conn, int handle) {
        // API call                                                                                                                          
    close_conn (handle, conn);
    delete conn;
  };
  auto delete_binded = std::bind (delete_conn, std::placeholders::_1, handle);
  return std::unique_ptr<int, decltype(delete_binded)> (conn, delete_binded);
}

int main()
{
  int handle = 2; // suppose                                                                                                                 
  auto c = get_conn (handle);
  if (!c)
    cout << "Unable to open connection\n";

  return 0;
};

如何将 auto 关键字替换为 std::unique_ptr 的实际 return 类型以与 c++11 兼容代码?

我尝试使用以下 return 类型但失败了

std::unique_ptr<int, void(*)(int *,int)> get_conn(int handle)
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
{
   // ...
}

你的 lambda 被传递到 std::bind,所以你得到另一个未命名的对象,你只知道它有 void (int*) 签名。

int因为绑定了第二个参数,所以像void(*)(int *,int)一样放在签名中是错误的。这个仿函数只接受指向 int 的指针。

使用std::function:

std::unique_ptr<int, std::function<void(int*)>>
get_conn (int handle)
{
  // API call                                                                                                                                
  int* conn = open_conn (handle);

  auto delete_conn = [](int *conn, int handle)
      {
        // API call                                                                                                                          
    close_conn (handle, conn);
    delete conn;
      };
  auto delete_binded = std::bind (delete_conn, std::placeholders::_1, handle);
  return std::unique_ptr<int, std::function<void(int*)> > (conn, delete_binded);
}

Demo

回到函子!

函数的 auto return 类型是 特征。为了提供实际的 return 类型,您可以提供如下仿函数(如评论中提到的 @IgorTandetnik)。优点是,您不再需要 std::bind

(See online)

struct DeleteConn  // functor which subsituts the lambda and `std::bind`
{
    int _handle;
    explicit DeleteConn(int handle): _handle{ handle } {}
    void operator()(int* conn) const
    {
        // API call                                                                                                                          
        close_conn(_handle, conn);
        delete conn;
    }
};

std::unique_ptr<int, DeleteConn> get_conn(int handle)
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---> now you can provide the actual type.
{
    // API call                                                                                                                                
    int* conn = open_conn(handle);
    DeleteConn delete_conn{ handle };
    return std::unique_ptr<int, DeleteConn>(conn, delete_conn);
}

或者,您可以将 lambda 函数 delete_connget_conn 函数中移出并使用 trailing return type which is a 特性。

(See Online)

namespace inter {
    auto delete_conn = [](int* conn, int handle)
    {
        // API call                                                                                                                          
        close_conn(handle, conn);
        delete conn;
    };
}

auto get_conn(int handle) 
->std::unique_ptr<int, decltype(std::bind(inter::delete_conn, std::placeholders::_1, handle))>
//  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --->Trailing return type
{
        // API call                                                                                                                                
        int* conn = open_conn(handle);
        auto delete_binded = std::bind(inter::delete_conn, std::placeholders::_1, handle);
        return std::unique_ptr<int, decltype(delete_binded)>(conn, delete_binded);
}