调试版本SEGFAULTs而Release版本有效 - 它是RVO吗?

时间:2017-10-24 13:27:36

标签: c++ c++11

我们有一个模板类,其中包含一些std::unique_ptr,其中一些是boost::asio

template <class cloud_type,
          bool  keep_alive   = true,
          class socket_type  = asio_http,
          class error_handle = default_error_handler>
class callable
{
    callable() = delete;
    // other stuff here, click the link to see actual code
private:
    // other members, most are unique pointers
    std::unique_ptr<boost::asio::io_service> io_;
};

它有two constructors,我们制作了一个包装函数,可以简化事情:

template <class cloud_type,
          bool  keep_alive   = true,
          class socket_type  = asio_http,
          class error_handle = default_error_handler,
          class ...args,
          typename = 
                typename std::enable_if<!std::is_same<cloud_type, 
                                                      cloud_batch>::value, bool>>
callable<cloud_type,keep_alive,socket_type,error_handle> 
    call(typename cloud_type::callback functor,
         args... params)
{
    return callable<cloud_type,
                    keep_alive,
                    socket_type,
                    error_handle>(functor, default_node, params...);
}

我们两个人在Ubuntu 16.04上使用G ++ 5.9和Boost 1.58对此进行了测试。 当我们构建Release版本(-O3)时,应用程序运行正常。 但是,当我们构建Debug版本时,应用程序SEGFAULTs。 我得到的实际错误是:

Thread 1 "human_detection" received signal SIGSEGV, Segmentation fault.
0x0000000000443128 in std::unique_ptr<boost::asio::io_service, std::default_delete<boost::asio::io_service> >::get (this=0x120) at /usr/include/c++/5/bits/unique_ptr.h:305
305           { return std::get<0>(_M_t); }

这似乎源于:

#0  0x0000000000443128 in std::unique_ptr<boost::asio::io_service, std::default_delete<boost::asio::io_service> >::get (this=0x120) at /usr/include/c++/5/bits/unique_ptr.h:305
#1  0x0000000000441880 in std::unique_ptr<boost::asio::io_service, std::default_delete<boost::asio::io_service> >::operator-> (this=0x120) at /usr/include/c++/5/bits/unique_ptr.h:298
#2  0x000000000043f2b4 in noos::cloud::callable<noos::cloud::human_detection, false, noos::cloud::asio_http, noos::cloud::default_error_handler>::send (this=0x0, timeout=0) at /home/zuperath/code/noos-api-maria/./noos/cloud/callable.tpl:120

指向:

void callable<cloud_type,
              keep_alive,
              socket_type,
              error_handle
             >::send(unsigned int timeout)
{
    assert(socket_ && query_ && resol_ && io_);
    if (!socket_)
        throw std::runtime_error("socket not set");
    if (!io_ || !query_ || !resol_)
        throw std::runtime_error("io, query or resolver not set");
    object.fill_buffer(boost::ref(*buffer_.get()), endpoint);
    socket_->is_connected() ? 
        socket_->send(*query_.get(), *resol_.get(), timeout, *buffer_.get()) :
        socket_->begin(*query_.get(), *resol_.get(), timeout);
    io_->run();
    io_->reset(); // here !!!
}

我试图了解我们做错了什么,并且我猜测Release使用了RVO,而Debug制作的副本导致了上述?

当我调用包装器时:

auto query = call<human_detection,false>(
                 [&](std::vector<noos::object::human> humans) {
                    std::cout << "Found " << humans.size() << " humans!" << std::endl;
                 }, pic);

错误在Debug期间仍然存在,而如果我直接调用类构造函数,则SEGFAULT会消失:

callable<human_detection,false> query([&](std::vector<noos::object::human> humans) {
                        std::cout << "Found " << humans.size() << " humans!" << std::endl;
                     }, default_node, pic);

我担心类的资源存在潜在问题(例如,boost::asio::io),这是通过使类可复制而启用的。

编辑:

我解决了SEGFAULT,这是由于一个lambda通过引用捕获,一个( this )正在被释放。 但是,我原来的问题仍然存在;为什么这会在DEBUG期间发生而不是RELEASE?

1 个答案:

答案 0 :(得分:2)

复制unique_ptr当然存在根本问题,但这是不可能的。这是唯一的重点。编译器通过禁用其复制ctor来强制执行此操作。因此,callable的默认复制构造函数也不存在。

但是看起来就像您的callable可以被复制一样。我怀疑发生的事情是你意外地写了一个转换构造函数:

callable::callable(callback functor, platform = default_node);

我怀疑您的callable可以转换为callback,并最终通过此路线进行复制。

根据经验,可以使用一个参数调用的构造函数(可能在添加默认值之后)应为explicit

BTW:您的其他ctor也有逻辑错误:

template <typename... parameters>
callable(callback functor,
         platform info = default_node,
         parameters... args);

究竟如何使用此默认值?它只能在提供单个参数时使用,但随后会出现重载决策,并且会选择第一个ctor。也就是说,它也是当前形式的潜在单一论证者,也应该是explicit

相关问题