我还应该在C ++ 11中返回const对象吗?

时间:2012-10-27 11:53:58

标签: c++ performance c++11 const

  

可能重复:
  Should I return const objects?
  (该问题的原始标题是: int foo()或const int foo()?解释我错过它的原因。)


有效的C ++,第3项:尽可能使用const。特别是,提升返回const对象以避免意外分配,如if (a*b = c) {。我发现它有点偏执,但我一直在遵循这个建议。

在我看来,返回const对象会降低C ++ 11中的性能。

#include <iostream>
using namespace std;

class C {
public:
    C() : v(nullptr) { }

    C& operator=(const C& other) {
        cout << "copy" << endl;
        // copy contents of v[]
        return *this;
    }

    C& operator=(C&& other) {
        cout << "move" << endl;
        v = other.v, other.v = nullptr;
        return *this;
    }

private:
    int* v;
};

const C const_is_returned() { return C(); }

C nonconst_is_returned() { return C(); }

int main(int argc, char* argv[]) {
    C c;
    c = const_is_returned();
    c = nonconst_is_returned();
    return 0;
}

打印:

copy
move

我是否正确实施了移动分配?或者我只是不应该在C ++ 11中返回const对象?

3 个答案:

答案 0 :(得分:25)

返回 const 对象是一种可能导致其他问题的解决方法。从C ++ 11开始,对于成员函数的赋值问题参考限定符,有一个更好的解决方案。我尝试用一​​些代码来解释它:

int foo(); // function declaration
foo() = 42; // ERROR

第二行中的赋值导致C和C ++中内置类型int的编译时错误。其他内置类型也是如此。那是因为内置类型的赋值运算符需要左侧的非const左值引用。要将它放在代码中,赋值运算符可能如下所示(无效代码):

int& operator=(int& lhs, const int& rhs);

在C ++中始终可以将参数限制为左值引用。但是,在C ++ 11之前,对于成员函数的隐式第一个参数(*this),这是不可能的。

使用C ++ 11改变了:类似于成员函数的 const限定符,现在有成员函数的引用限定符。以下代码显示了复制和移动运算符的用法(请注意参数列表后面的&):

struct Int
{
    Int(const Int& rhs) = default;
    Int(Int&& rhs) noexcept = default;
    ~Int() noexcept = default;
    auto operator=(const Int& rhs) & -> Int& = default;
    auto operator=(Int&& rhs) & noexcept -> Int& = default;
};

使用此类声明时,以下代码片段中的赋值表达式无效,而赋值给局部变量则起作用 - 就像在第一个示例中那样。

Int bar();
Int baz();
bar() = baz(); // ERROR: no viable overloaded '='

因此不需要返回const对象。您可以将赋值运算符限制为左值引用,以便其他所有内容仍然按预期工作 - 特别是移动操作。

另见:

答案 1 :(得分:22)

即使在C ++ 11之前,按值返回const对象可能也不是一个好主意。它唯一的作用是它阻止调用者在返回的对象上调用非const函数 - 但这并不是非常相关,因为调用者无论如何都收到了对象的副本

虽然返回一个常量对象确实会阻止调用者错误地使用它(例如错误地进行赋值而不是比较),但是函数决定调用者如何使用它不应该是函数的责任。返回的对象(除非返回的对象是函数所拥有的结构的引用或指针)。 函数实现者不可能知道返回的对象是用于比较还是其他用途。

你也是对的,在C ++ 11中问题甚至更严重,因为返回const有效地阻止了移动操作。 (但它并不妨碍复制/移动省略。)

当然,当函数返回引用或指针时,同样重要的是指出const仍然非常有用(并且使用它没有偏执的迹象)。

答案 2 :(得分:3)

您致const_is_returnedcopy constructor而不是move constructor的原因是move必须修改对象,因此无法在{{{}}上使用const 1}}对象。我倾向于说在任何情况下都不建议使用const并且应该接受程序员的判断,否则你得到你所展示的东西。好问题。