【问题标题】:Why is this pointer needed when calling std::call_once()?为什么调用std :: call_once()时需要这个指针?
【发布时间】:2014-06-05 12:20:06
【问题描述】:

在《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()的参数。鉴于X::open_connection() 没有输入参数,为什么在调用std::call_once() 时需要this 指针?

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


更新:在“C++ Concurrency in Action”一书的第 4.2.1 节中在引入类似功能时进一步明确解决了此问题,即std::async

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

【问题讨论】:

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


    【解决方案1】:

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

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

    它可以被不同的实例调用,尽管在这种情况下这没有意义:

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

    【讨论】:

    • 所以就相当于调用this-&gt;open_connection()吧?
    • @herohuyongtao 会导致this-&gt;open_connection()被调用一次。
    • 第三个参数不应该是call_once()的第二个参数所指示的函数的输入参数吗,比如here的例子?
    • @herohuyongtao 是也不是。这些示例具有非成员函数。成员函数有一个隐含的this 的第一个参数。这就是对象的状态可以在其中访问的方式。但call_once(和std::threadstd::bind 等)不是成员函数,因此它们需要显式传递第一个参数。这是他们可以将成员函数绑定到实例的唯一方法。
    • 现在清除。感谢您的详细解释。
    【解决方案2】:

    juanchopanza 是正确的,我想补充一点,如果您将参数或代码 sn-p 替换为严格等效的 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(); } );
    

    【讨论】:

      猜你喜欢
      • 2011-03-29
      • 2014-11-25
      • 2019-06-22
      • 1970-01-01
      • 2012-08-09
      • 1970-01-01
      • 2021-10-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多