【问题标题】:In place constrution of member variable via constructor通过构造函数就地构造成员变量
【发布时间】:2011-08-08 19:29:42
【问题描述】:

参加以下课程:

template <typename TPayload>
class Message
{
    public:
        Message(const TPayload& payload)
             : m_header(sizeof(TPayload)),
               m_payload(payload) {}

    private:
        const Header   m_header;
        const TPayload m_payload;
};

每当我构造一个消息时,我必须创建一个 TPayload(参数负载),将其复制到 m_payload,然后销毁负载。现在考虑一下这可以每秒完成 100'000 次,我认为这是一种浪费的努力。

我的问题是,我可以强制 m_payload 就地构造来避免临时有效负载吗?

我正在考虑的一个可能的解决方案是多次重载构造,如下所示,但老实说,我怀疑是否有很多节省。

template <typename TPayload>
class Message
{
    public:
        template <typename A>
        Message(const A& a)
             : m_header(sizeof(TPayload)),
               m_payload(a) {}

        template <typename A, typename B>
        Message(const A& a, const B& b)
             : m_header(sizeof(TPayload)),
               m_payload(a, b) {}

    private:
        const Header   m_header;
        const TPayload m_payload;
};

【问题讨论】:

  • 这是伪代码吗?您应该在发布之前尝试编译代码,或者至少应该提到这是伪代码,因此不会编译。
  • 这是对我正在编写的类的简化,更多用于演示目的。更正了一些丢失的括号:)
  • 不仅括号不见了,代码甚至是正确的。如果您发布此内容,我们将如何推断看到您的代码您已经知道多少?表明我看到了您的代码,您没有使用模板,也从未使用它编写过代码。
  • 如果您使用临时对象构造消息,例如:Message&lt;Foo&gt;(Foo(bar)),优化器将消除冗余副本,并应有效地“就地”构造对象。我对此不是 100% 确定的。如果我错了,我肯定会被揍。

标签: c++ construction in-place


【解决方案1】:

您正在寻找的是转发Message的构造函数参数到Message::m_payload的构造函数。

这可以在 C++11 中巧妙地完成(使用可变参数模板和 std::forward,在 std::vector&lt;&gt;::emplace_back() 和许多其他函数中使用)或在 C++03 中使用几个重载,当你开始编写时,以及用过in boost::make_shared&lt;&gt;

例如:

#include <iostream>
#include <string>
#include <utility>
typedef size_t Header;
template <typename TPayload>
class Message
{
    public:
        template <typename ...Args>
        Message(Args&&... args)
             : m_header(sizeof(TPayload)),
               m_payload(std::forward<Args>(args)...)
               {}
        void show_payload() const
        {
                std::cout << m_payload << '\n';
        }
    private:
        const Header   m_header;
        const TPayload m_payload;
};

int main()
{
     Message<std::string> test(10, 'a');
     test.show_payload();

     Message<double> test2(3.14);
     test2.show_payload();
}

试运行:https://ideone.com/J1JnZ

【讨论】:

    【解决方案2】:

    同样在C++11中,你可以通过值接受参数,然后移动构造它:

    Message(TPayload payload)
        :m_header(sizeof(TPayload)),
         m_payload(std::move(payload)) {}
    

    只要确保 TPayload 有一个正确定义且有用的移动构造函数,否则这不会有什么好处。

    【讨论】:

    • +1 这也适用于 C++ 03,只是你必须默认构造有效负载成员,然后使用参数swap() 它。当然,这意味着有效负载必须有一个默认构造函数。或者至少是一个非常“便宜”的构造函数——即一个不做太多事情的构造函数(不分配内存等)。
    • @pgroke 并且该成员必须是非常量。
    • @Mark B:对。我没看到。不过应该可以安排。
    猜你喜欢
    • 2014-05-08
    • 2017-06-23
    • 2013-11-18
    • 2011-09-13
    • 2018-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-19
    相关资源
    最近更新 更多