gpt4 book ai didi

C++11 最佳实践 : When to accept by value vs const&?

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:58:04 25 4
gpt4 key购买 nike

我对以下“规则”感到满意:当您打算存储 对象时按值接受,而当您只需要访问它时按常量引用接受。这样,您(类的编写者)不会选择是否复制类变量的用户或是否 move 它,他们会选择。但在使用过程中,我越来越不确定这个建议是否正确; move 在成本操作上不是统一的...

struct Thing
{
std::array<int, 10000> m_BigArray;
};

class Doer
{
public:
Doer(Thing thing) : m_Thing(std::move(thing)) {}

private:
Thing m_Thing;
};

int main()
{
Thing thing;
Doer doer1(std::move(thing)); // user can decide to move 'thing'
// or
Doer doer2(thing); // user can decide to copy 'thing'
}

在上面的例子中, move 和复制一样昂贵。因此,不是采用 const 引用并复制对象一次,而是最终 move 它(有效地复制它)两次。用户对你的论点做了一次,然后你又对你的成员做了一次。

即使 move 比复制便宜得多,这种情况也会进一步恶化(假设 move 的东西是下面的一些未知成本,但比复制便宜):

struct A
{
A(Thing thing) : m_Thing(std::move(thing)) {}
Thing m_Thing;
};

struct B : A
{
B(Thing thing) : A(std::move(thing)) {}
};

struct C : B
{
C(Thing thing) : B(std::move(thing)) {}
};

struct D : C
{
D(Thing thing) : C(std::move(thing)) {}
};

在这里,您将得到 1 个拷贝和 4 个 move ,或 5 个 move 。如果所有的构造函数都接受一个 const 引用,那么它只会是 1 个拷贝。现在我必须权衡什么走法昂贵,1 个拷贝还是 5 个走法。

处理这些情况的最佳建议是什么?

最佳答案

What's the best advice for handling these situations?

我最好的建议是做你正在做的事情:为自己考虑。不要相信你听到的一切。测量。

下面我获取了您的代码并使用打印语句对其进行了检测。我还添加了第三种情况:从纯右值初始化:

测试以两种方式尝试:

  1. 按值传递。
  2. 通过 const&&& 传递时重载:

代码:

#include <utility>
#include <iostream>

struct Thing
{
Thing() = default;
Thing(const Thing&) {std::cout << "Thing(const Thing&)\n";}
Thing& operator=(const Thing&) {std::cout << "operator=(const Thing&)\n";
return *this;}
Thing(Thing&&) {std::cout << "Thing(Thing&&)\n";}
Thing& operator=(Thing&&) {std::cout << "operator=(Thing&&)\n";
return *this;}
};

class Doer
{
public:
#if PROCESS == 1
Doer(Thing thing) : m_Thing(std::move(thing)) {}
#elif PROCESS == 2
Doer(const Thing& thing) : m_Thing(thing) {}
Doer(Thing&& thing) : m_Thing(std::move(thing)) {}
#endif

private:
Thing m_Thing;
};

Thing
make_thing()
{
return Thing();
}

int main()
{
Thing thing;
std::cout << "lvalue\n";
Doer doer1(thing); // user can decide to copy 'thing'
std::cout << "\nxvalue\n";
Doer doer2(std::move(thing)); // user can decide to move 'thing'
std::cout << "\nprvalue\n";
Doer doer3(make_thing()); // user can decide to use factor function
}

对我来说,当我使用 -DPROCESS=1 编译时,我得到:

lvalue
Thing(const Thing&)
Thing(Thing&&)

xvalue
Thing(Thing&&)
Thing(Thing&&)

prvalue
Thing(Thing&&)

还有 -DPROCESS=2:

lvalue
Thing(const Thing&)

xvalue
Thing(Thing&&)

prvalue
Thing(Thing&&)

因此,对于左值和 xvalue 情况,通过值传递比通过重载引用传递需要额外的 move 构造。正如您所指出的,搬家建筑不一定便宜。它可能与复制构造一样昂贵。从好的方面来说,您只需编写 1 个按值传递的重载。通过重载引用传递需要 2^N 次重载,其中 N 是参数的数量。在 N==1 时相当可行,在 N==3 时变得笨拙。

另外,正如您所指出的,您的第二个示例只是您的第一个示例。

当性能是您最关心的问题时,尤其是当您不能指望便宜的 move 构造函数时,请传递重载的右值引用。当您可以依靠便宜的 move 构造,和/或您不想处理不合理的(您可以为自己定义不合理的)重载数量时,请使用按值传递。没有一个答案在任何情况下都对每个人都是正确的。 C++11 程序员仍然需要思考。

关于C++11 最佳实践 : When to accept by value vs const&?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14921364/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com