64

考虑一个X具有N成员变量的类,每个变量都有一些可复制可移动的类型,以及N相应的 setter 函数。在 C++98 中, 的定义X可能如下所示:

class X
{
public:
    void set_a(A const& a) { _a = a; }
    void set_b(B const& b) { _b = b; }
    ...
private:
    A _a;
    B _b;
    ...
};

上述类的 Setter 函数X可以绑定到左值和右值参数。根据实际参数,这可能会导致创建临时文件并最终导致复制分配;因此,此设计不支持不可复制的类型。

在 C++11 中,我们拥有移动语义、完美转发和通用引用(Scott Meyers 的术语),通过以下方式重写 setter 函数,可以更高效、更通用地使用它们:

class X
{
public:
    template<typename T>
    void set_a(T&& a) { _a = std::forward<T>(a); }

    template<typename T>
    void set_b(T&& b) { _b = std::forward<T>(b); }
    ...
private:
    A _a;
    B _b;
    ...
};

通用引用可以绑定到const/non- constvolatile/non-volatile和任何一般的可转换类型,避免创建临时变量并将值直接传递给operator =. 现在支持不可复制可移动的类型。可以通过static_assert或 通过消除可能不需要的绑定std::enable_if

所以我的问题是:作为设计指南,C++11 中的所有(比如说,大多数)setter 函数都应该写成接受通用引用的函数模板吗?

除了更繁琐的语法和在那些 setter 函数中编写代码时无法使用类似 Intellisense 的帮助工具之外,假设原则“将 setter 函数编写为函数模板,尽可能接受通用引用”是否有任何相关的缺点?

4

1 回答 1

36

您知道 A 类和 B 类,因此您知道它们是否可移动,以及这种设计是否最终是必要的。对于类似的东西std::string,除非你知道你在这里有性能问题,否则更改现有代码是浪费时间。如果您正在处理 . auto_ptr,那么是时候将其撕掉并使用unique_ptr.

如果您不知道更具体的内容,现在通常首选按值获取参数 - 例如

void set_a(A a) { _a = std::move(a); }

这允许使用任何构造函数,A除了可移动性之外不需要任何东西,并提供相对直观的界面。

于 2013-01-07T14:10:25.223 回答