【问题标题】:make_shared doesn't play along with enable_shared_from_this?make_shared 不能与 enable_shared_from_this 一起使用?
【发布时间】:2018-09-05 07:06:26
【问题描述】:

考虑以下两个代码sn-ps, 第一个:

#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;
}

第二个和第一个只有一行不同,即注释行。

使用 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. 还是其他原因?

【问题讨论】:

  • 请将示例编辑为minimal reproducible example。你不需要boost::asio来演示问题,类定义是非法的。
  • std::make_sharedstd::enable_shared_from_this 配合得很好,这本身不应该是问题。
  • make_shared 无法工作,因为您的构造函数是私有的,但无法重现您的不完整类型错误,请提供 minimal reproducible example

标签: c++ boost-asio shared-ptr


【解决方案1】:

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

当您编写 new tcp_connection(io_service) 时,构造函数在 tcp_connection 本身的范围内被引用,它具有访问权限。

但是,std::make_shared(或它可能采用的任何实现细节)无权访问私有构造函数,因此它无法初始化它打算让共享指针管理的对象。

如果初始化格式正确,std::make_sharedstd::enable_shared_from_this 配合得非常好,但私有构造函数会导致格式错误。

对此的常见解决方法是使用Passkey idiom。这归结为一个公共 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
    {
    }
};

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

【讨论】:

  • 您可以添加对 key-pass 习惯用法的引用以仍然限制构造函数访问,即使为了使用std::make_shared 而公开?无论如何,+1。
  • @lubgr - 我只是在寻找对此的参考。现已添加,谢谢:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-18
  • 1970-01-01
  • 1970-01-01
  • 2017-01-09
  • 2017-04-14
  • 2016-09-16
相关资源
最近更新 更多