C++14:如何设计二传手?

C++14: How to design setters?

假设我有一个相当大的 class A,其中有另一个 class B:

的成员
class A {
    various large data members here
}


class B {
    public:
      setA( .... );
    private:
       A a;
}

B 中的 A 成员编写 setter 的最佳方法是什么(在速度和代码整洁度方面)?

第一个选项是典型的 C++98 风格:

void setA(const A& a) { this.a = a; }

并像

一样使用它
B b;
A a;
b.setA(a);

这至少需要一份副本,这可能会很昂贵。对于大对象更有效的可能是指针:

class B {
    public:
      setA( .... );
    private:
       A *a;
}

setA(A *a) { this->a = a; }

B b;
A *a = new A();
b.setA(a);

这伴随着指针的所有麻烦,必须编写自定义析构函数等。在 C++14 中,可以使用 std::uniuqe_ptr,但这仍然比简单地拥有一个非指针成员要干净得多在 B.

中的 A

在 C++14 中,可能有使用 rvalues 的选项,并通过简单的按值调用移动语义,即

void setA(A a) { this.a = std::move(a); }

并这样称呼它:

B b;
A a;
b.setA(std::move(a));  // if we don't need a anymore

这很好,很干净,应该很快,但是:

Herb Sutter 在他关于回到基础知识的幻灯片中的论点!你通常应该喜欢的现代 C++ 风格的精要

void setA(const A& a) { this.a = a; } 

但他在演讲中谈到了一个相当小的成员(字符串),因此对于更大、更复杂的对象,这可能不适用...

正确的做法是什么(在 Java 中,这很简单...)

您的对象在构建后应该可以使用了。为什么在构建class B 时不通过class A?

#include <memory>

class A
{
public:
    A(int a) : a{ a } {}
private:
    int a;
};

class B
{
public:
    B(int b, A a) : b{ b }, a{ std::make_unique<A>(a) } {}
private:
    int b;
    std::unique_ptr<A> a;
};

int main()
{
    B b(int{ 4 }, A{ 1 });
}

你可以有两个 setter,一个用于右值引用,另一个用于 const&,如下所示:

void setA(const A& a) { a_ = a; } 
void setA(A&& a) { a_ = std::move(a); }

或者,如果您不打算将 setA 与任何其他类型一起使用,您可以使用通用引用:

template<typename T>
void setA(T&& a_) { a_ = std::forward<T>(a); }

但是既然你已经允许设置这个值,你不妨考虑一下public,这样你就完全不用担心设置器了。