在传递unique_ptr时,调试和发布配置中的不一致动作?

问题描述

所以我得到了一些使用SFML库处理一些简单tcp套接字的代码。因此,在SFML功能的使用下创建了一个套接字,并从一个函数中返回了该套接字作为右值引用。 然后,组织功能将这个套接字传递给(当前仅用于存储),并通知调用者是否已处理套接字。但是,这无法正常工作。

struct Tcpsocket : public ::sf::Tcpsocket {};

unique_ptr<Tcpsocket>&& TcpListener::nonBlockingNext() 
{
    unique_ptr<Tcpsocket> new_socket (new Tcpsocket) ;
    listener.setBlocking(false);
    if( listener.accept(*new_socket) == ::sf::Socket::Status::Done) 
    {
        new_socket->setBlocking(false);
        std::cout << "Connection established! " << new_socket.get() << "\n";
        return std::move(new_socket);
    }
    return std::move( unique_ptr<Tcpsocket>(nullptr) );
}

bool ConnectionReception::processNextIncoming()
{
    unique_ptr<Tcpsocket> new_socket (listener.nonBlockingNext());
    std::cout << " and then " << new_socket.get() << "\n";
    if( !new_socket ) return false;

    processNewTcpConnection( ::std::move(new_socket) );
    return true;
}

先前使用的TcpListener类在组合中封装了sf :: TcpListener并简单地转发其用法

我有一个简单的测试,尝试连接。

TEST(test_NetworkConnection,single_connection)
{
    ConnectionReception reception;

    reception.listen( 55555 );
    std::this_thread::sleep_for( 50ms );

    Tcpsocket remote_socket;
    remote_socket.connect( "127.0.0.1",55555 );

    std::this_thread::sleep_for( 10ms );
    EXPECT_TRUE( reception.processNextIncoming() );
}

此测试在我正在编译的两种配置中均以不同的方式失败。 在调试(g++ -g3中,测试意外失败。

[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from test_NetworkConnection
[ RUN      ] test_NetworkConnection.single_connection
Connection established! 0x6cf7ff0
 and then 0
test\test_NetworkConnection.cpp:24: Failure
Value of: reception.processNextIncoming()
  Actual: false
Expected: true
[  Failed  ] test_NetworkConnection.single_connection (76 ms)
[----------] 1 test from test_NetworkConnection (78 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (87 ms total)
[  PASSED  ] 0 tests.
[  Failed  ] 1 test,listed below:
[  Failed  ] test_NetworkConnection.single_connection

 1 Failed TEST

调试和输出显示,已经到达nonBlockingNext()的第一个返回,即返回侦听器接受的套接字的返回,但是在随后的processNextIncoming外部函数中,{ {1}}未设置/ new_socket是。

在Release中,即与nullptr一起输出显示承诺,但测试本身因段错误而崩溃,看似在测试拆解中,也许是在释放套接字(我通过进一步的输出确定)时进行了调试,代码不是很成功。

g++ -O3

在-g3编译中进行调试时,我还注意到在'nonBlockingNext()'中[==========] Running 1 test from 1 test suite. [----------] Global test environment set-up. [----------] 1 test from test_NetworkConnection [ RUN ] test_NetworkConnection.single_connection Connection established! 0xfe7ff0 and then 0xfe7ff0 的构造在返回之前似乎又达到了:

new_socket

最有可能在发布配置中进行了优化的步骤,或者只是gdb变得很奇怪。

出了什么问题?我该如何进行这项工作?我在右值和移动时是否犯了任何错误

解决方法

您在这里有未定义的行为:

unique_ptr<TcpSocket>&& TcpListener::nonBlockingNext() 
{
    unique_ptr<TcpSocket> new_socket (new TcpSocket) ;
    //...
    if( /*...*/) 
    {
        //...
        return std::move(new_socket);
    }
    //...
}

问题是您正在返回对局部变量(new_socket)的引用。不要因为它是一个右值引用而分心-它仍然是一个引用!您应该改为按值返回unique_ptr。而且,即使std::move()返回的值合法,但充其量是没有用的,或者最差的情况是错过了优化-因此,只需将其设为return new_socket