make_shared与enable_shared_from_this不一起玩?

Joh*_* Li 2 c++ shared-ptr boost-asio

考虑以下两个代码片段,第一个:

#include "pch.h"
#include <memory>
#include <boost/asio.hpp>

using boost::asio::ip::tcp;

class tcp_connection : public std::enable_shared_from_this<tcp_connection>
{
public:
    typedef std::shared_ptr<tcp_connection> pointer;

    static pointer create(boost::asio::io_service& io_service)
    {
        return pointer(new tcp_connection(io_service));
        //second example only differs by replacing the above line with the below one
        //return std::make_shared<tcp_connection>(io_service);
    }

private:
    tcp_connection(boost::asio::io_service& io_service) //private constructor
        : socket_(io_service)
    {
    }
    tcp::socket socket_;
};

int main()
{
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

第二个与第一个不同,只有一行,即注释行.

使用MSVC 2017和boost :: asio 1.68,第一个版本按预期工作,而第二个版本不编译,吐出错误,例如"不允许不完整类型tcp_async".

我的问题是:

  1. 这是因为std :: make_shared不能与std:std :: enable_shared_from_this一起玩吗?
  2. 或者,这是因为asio持有关于如何实现std :: make_shared或std :: enable_shared_from_this的假设,并不适用于MSVC 2017.
  3. 或者它是另一回事?

Sto*_*ica 6

您显示的代码中的问题源于您的类型的构造函数是私有的.

当你编写new tcp_connection(io_service)构造函数时,在tcp_connection自己的范围内引用它,它具有访问权限.

但是,std::make_shared(或者它可能采用的任何实现细节)都无法访问私有构造函数,因此它无法初始化它意味着拥有共享指针的对象.

如果初始化格式正确,std::make_shared可以很好地工作std::enable_shared_from_this,但是私有构造函数会使其形成错误.

一个常见的解决方法是使用Passkey习语.这可以归结为公共c'tor,但是接受私有类型的参数.它有点像这样1:

class tcp_connection2: public std::enable_shared_from_this<tcp_connection2>
{
    struct key{ explicit key(){} };
public:
    typedef std::shared_ptr<tcp_connection2> pointer;

    static pointer create(int io_service)
    {
        return std::make_shared<tcp_connection2>(io_service, key{});
    }

    tcp_connection2(int io_service, key) //private constructor, due to key
    {
    }
};
Run Code Online (Sandbox Code Playgroud)

1 - 我稍微修改了你的类定义,以便其他人更容易复制,粘贴和测试它.但是同样的原则可以应用于您的代码.