1

在 C++11 之前,我会这样编写函数:

struct Color {
    float R,G,B,A;
    Color(float NewR,float NewG,float NewB,float NewA):
        R(NewR),G(NewG),B(NewB),A(NewA)
};
struct Item {
    Color color;

    void SetColor(const Color& new_color)
    {
        color=new_color; // Copy is created
    }
};

然后这样称呼它:

a_item.SetColor(Color(1.0f,1.0f,1.0f,1.0f));

Color new_color(1.0f,0.0f,0.0f,1.0f); // alternative way 
a_item.SetColor(new_color);

现在使用 C++11,我在适用时编写这样的函数:

struct Item {
    Color color;

    void SetColor(Color new_color)
    {
        color=std::move(new_color); // No extra copy is created
    }
};

然后这样称呼它:

a_item.SetColor(Color(1.0f,1.0f,1.0f,1.0f)); // already Rvalue

Color new_color(1.0f,0.0f,0.0f,1.0f); // alternative way 
a_item.SetColor(std::move(new_color));

我想知道这是否是一个好习惯。似乎当对象所有权被转移时,我的函数变成了具有移动语义的按值传递。

说到 const 正确性,我的构造函数是否应该这样定义:

    Color(const float NewR,const float NewG,const float NewB,const float NewA):
        R(NewR),G(NewG),B(NewB),A(NewA)

我的 SetColor 函数是这样定义的?:

    void SetColor(const Color new_color)
    {
        color=std::move(new_color); // No extra copy is created
    }
4

2 回答 2

4

关于第一部分,这似乎基本没问题,但请阅读本答案的结尾。对于第二部分,您首先应该知道顶层const是从函数的签名中剥离出来的。所以这

void foo( Color c );

等同于

void foo( const Color c );

因此,对于调用者来说,它没有任何区别。唯一的区别是当你定义函数时,如果你const为定义添加一个参数,编译器不会修改它。这在您提出问题的上下文中没有意义:如果您想将实例移动到其他地方,它不是const.

如果您认为const是正确的方法,请使用 const 引用。现在回到你的第一个问题:使用void f( Color c );似乎很容易,在某些情况下,避免了多余的副本。问题是这在所有情况下和今天的编译器上都不起作用。与重载const Color&和相比Color&&,有时会产生额外的移动。唯一的好处是您需要更少的重载,一旦您有多个参数,这可能变得很重要。

用代码解释区别:

void X::f( Color c )
{
   this->c = std::move(c); // 1 move=
}

void X::g( const Color& c )
{
   this->c = c; // 1 copy=
}

void X::g( Color&& c )
{
   this->c = std::move(c); // 1 move=
}

X x;
Color c;
x.f(c); // 1 copy-ctor, 1 move=
x.g(c); // 1 copy=
x.f(Color()); // 1 ctor, 1 move=
x.g(Color()); // 1 ctor, 1 move=
x.f(std::move(c)); // 1 move-ctor, 1 move=
x.g(std::move(c)); // 1 move=

如您所见,使用 const 引用与 C++11 右值引用重载相结合的“传统”方式在移动操作的数量上具有优势(这仍然是有成本的)。平衡它与没有超载的简化并自己判断。

于 2013-10-27T18:46:46.973 回答
1

我将把“完美的转发设置器”技术加入到组合中:

struct Item {
    Color color;

    template <typename T>
    void SetColor(T&& new_color)
    {
        color=std::forward<T>(new_color);
    }
};

这将从右值移动,从左值复制,甚至接受其他可转换为Color.

于 2013-10-28T06:04:13.050 回答