调用std :: call_once()时为什么需要这个指针?

时间:2014-04-21 12:20:13

标签: c++ multithreading pointers c++11 this-pointer

在书“C ++ Concurrency in Action”§3.3.1中,当使用std::call_once()引入类成员的线程安全延迟初始化时,它给出了以下示例:

#include <mutex>

struct connection_info
{};

struct data_packet
{};

struct connection_handle
{
    void send_data(data_packet const&)
    {}
    data_packet receive_data()
    {
        return data_packet();
    }
};

struct remote_connection_manager
{
    connection_handle open(connection_info const&)
    {
        return connection_handle();
    }
} connection_manager;


class X
{
private:
    connection_info connection_details;
    connection_handle connection;
    std::once_flag connection_init_flag;

    void open_connection()
    {
        connection=connection_manager.open(connection_details);
    }
public:
    X(connection_info const& connection_details_):
        connection_details(connection_details_)
    {}
    void send_data(data_packet const& data)
    {
        std::call_once(connection_init_flag,&X::open_connection,this);
        connection.send_data(data);
    }
    data_packet receive_data()
    {
        std::call_once(connection_init_flag,&X::open_connection,this);
        return connection.receive_data();
    }
};

int main()
{}

its doc开始,第三个参数是传递给函数X::open_connection()的参数。在this没有输入参数的情况下,为什么在调用std::call_once()时需要X::open_connection()指针?

std::call_once(connection_init_flag,&X::open_connection,this);

P.S。:删除this指针将导致C2064错误:

  

error C2064: term does not evaluate to a function taking 0 arguments


更新:在引入类似功能(即std::async)时,“C ++并发操作”一书的§4.2.1中进一步明确了这个问题:

  

如果第一个参数(应该是std::call_once的第二个参数)是指向成员函数的指针,则第二个参数(应该是std::call_once的第三个参数)提供对象在其上应用成员函数(直接,或通过指针,或包含在std::ref),其余的参数作为参数传递给成员函数。否则,第二个(应该是std::call_once)的第三个参数和后续参数作为参数传递给指定为第一个参数的函数或可调用对象。

2 个答案:

答案 0 :(得分:12)

  

调用std :: call_once()时为什么需要这个指针?

因为open_connection是非静态数据成员。它必须在某个东西上被调用,并且某些东西是同一个实例,由this指向(技术上,非静态成员函数具有this的隐式第一个参数。)

可以使用不同的实例调用它,虽然在这种情况下这没有意义:

X x;
std::call_once(connection_init_flag, &X::open_connection, &x);

答案 1 :(得分:5)

juanchopanza是正确的,我想补充一点,如果你用严格等效的lambda替换参数或你的代码片段,你实际上做的可能会更清楚:

std::call_once(connection_init_flag, [&]{ open_connection(); } );
// or 
std::call_once(connection_init_flag, [this]{ open_connection(); } );

这也完全等同于:

std::call_once(connection_init_flag, [this]{ this->open_connection(); } );