標籤:

C++ string + 號返回的是右值,為什麼下面這段代碼不報錯?

#include &
#include &
using namespace std;

int main()
{
string s1 = "Hello";
string s2 = "world";

cout &<&< (s1 + s2 = "OK") &<&< endl; int i = 0; int j = 20; //cout &<&< (i + j = 30) &<&< endl; }

為什麼輸出能OK? 同是右值,我覺得應該會和下面int一樣報錯.


int是內置類型,和string不一樣。

i + j 的結果被放在一個臨時的空間里,對這個空間不能進行賦值操作。

比如,你不能這樣:int ref = i + j; 但是可以這樣:const int cref = i + j;

即,標準規定了內置類型的右值是不能改變的。

s1 + s2 的結果是一個臨時對象,這個臨時對象會在cout &<&< (s1 + s2 = "OK") &<&< endl;這句的分號結束後變得無效。

你在這裡進行的賦值操作,其實是:(s1 + s2).operator=("OK")。用一個右值調用成員函數是可以的,只不過沒意義:你把「OK」賦值給了臨時對象,這句話結束後臨時對象失效。這等於你做了一件無用功。

由於string::operator會返回賦值運算符左側值,所以cout出來的是「OK」。

總之,為什麼不報錯呢?

因為在cout這句話的分號之前,臨時對象還是存在的。


string相加產生了一個臨時對象,相當於對一個臨時對象賦值,是沒有意義的,C++ 11之前沒有區分左值和右值的語法元素,無法限定assignment operator只能作用於右值。C++ 11中可以阻止這種操作:

struct Foo
{
void callByLvalueOnly() // 限定該成員函數只能被左值調用
{
}

void callByRvalueOnly() // 限定該成員函數只能被右值調用
{
}

Foo operator=(const Foo) // 限定了只能對左值進行賦值
{
}
};

Foo newFoo()
{
return Foo();
}

int main()
{
// newFoo() 為右值
newFoo() = Foo(); // compile error, 阻止了對右值進行賦值
newFoo().callByLvalueOnly(); // compile error
newFoo().callByRvalueOnly(); // OK

Foo foo = newFoo();
// foo為左值
foo = Foo(); // OK, 對左值進行賦值
foo.callByLvalueOnly(); // OK
foo.callByRvalueOnly(); // error
}


因為string重載了賦值操作符。以下摘自距C++ 14最接近的標準草案N4296:

[expr] 3 ... Overloaded operators obey the rules for syntax specified in Clause 5, but the requirements of operand type, value category, and evaluation order are replaced by the rules for function call.


參見博客C++ 中臨時對象 和 const 對象 的一個區別

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 下測試通過


c++11 支持右值引用

//ostream operator &<&<(ostream , string ){}


應該是你的編譯器版本是C艹11之前的吧,string重載了=,所以不會抱【右值】無法【賦值】的錯誤


推薦閱讀:

關於指針數組的初始化的一個問題?
為什麼C++的庫函數的定義會這麼複雜?
如何才能寫出沒有bug的程序?
為什麼OJ上有些人提交的代碼運行那麼快? 有人總結這些技巧么
如何解決 C++ 代碼不能打開提示有一個錯誤的問題?

TAG:編程 | C |