2011-08-21 56 views
3

我有習慣(?!?!?)將所有東西都返回爲「const」值。像這樣...移動語義並返回常量值

struct s; 

s const make_s(); 

s const &s0 = make_s(); 
s const s1 = make_s(); 

隨着移動操作和r值引用和以下功能...

void take_s(s &&s0); 
void take_s(s const &&s0); // Doesn't make sense 

我不能再寫......

take_s(make_s()); 

的主要原因我開始使用返回const值的約定是爲了防止有人寫這樣的代碼...

make_s().mutating_member_function(); 

使用情況如下...

struct c_str_proxy { 
    std::string m_s; 

    c_str_proxy(std::string &&s) : m_s(std::move(s)) { 
    } 
}; 

c_str_proxy c_str(std::string &&s) { 
    return c_str_proxy(s); 
} 

char const * const c_str(std::string const &s) { 
    return s.c_str(); 
} 

std::vector <std::string> const &v = make_v(); 
std::puts(c_str(boost::join(v, ", "))); 

std::string const my_join(std::vector <std::string> const &v, char const *sep); 

// THE FOLLOWING WORKS, BUT I THINK THAT IS ACCIDENTAL 
// IT CALLS 
// 
//  c_str(std::string const &); 
// 
// BUT I THINK THE TEMPORARY RETURNED BY 
// 
//  my_join(v, "; ") 
// 
// IS NO LONGER ALIVE BY THE TIME WE ARE INSIDE 
// 
//  std::puts 
// 
// AS WE ARE TAKING THE "c_str()" OF A TEMPORARY "std::string" 
// 
std::puts(c_str(my_join(v, "; "))); 

看上去彷彿「返回常量的值」和R值引用並不在這個特定用例混合。是對的嗎?

**Edit 0: Extra question...** 

無論如何,該對象是臨時的。爲什麼要「const」防止移動?爲什麼我們不能移動「const」臨時對象?

+3

我真的沒有看到首先返回const值的基本原理。你爲什麼會在乎阻止人們在返回的對象上調用變異成員函數? – jalf

+2

常量值返回習慣用法的一個例子可以在Meyers的「更有效的C++」中找到,1996,第6項。Meyers推薦'const T operator ++(int)'作爲postfix ++的簽名。 –

回答

11

你有兩個相互衝突的目標。一方面,您想阻止對返回對象進行修改,但另一方面,您想要允許修改(這是一個移動操作。它修改源對象,通過盜竊其內部資源)。

你需要做出決定。你希望這個對象是不可變的,還是你希望人們能夠修改它?

對於什麼是值得的,我並不真正看到你通過首先返回const臨時對象會獲得什麼。是的,你可以防止人們調用它的變異成員函數,但是爲什麼你想要?充其量,能夠做到這一點是有用的,而在最壞的情況下,這是一個容易避免的錯誤。

而你在做什麼並沒有多大意義。在臨時的整個點是它會在一瞬間消失,所以誰在乎如果它被修改?

右值引用和移動語義背後的整個想法是臨時對象是臨時的,所以它們可以被修改而不會傷害任何人。

+3

是的。唯一的情況是當你想要返回一個const的時候,它是一個引用或一個指向你不希望調用者能夠改變的對象的指針。否則,讓他們離開。 – AFoglia

+0

實際上,返回const rvalues對於防止如下錯誤非常有用: if(a * b = c) 如果a * b的類型可以用c賦值並且可以隱式轉換爲bool ... well。這是一種邊緣情況,但通過將用戶類型作爲常量返回很容易避免。 在vc14編譯器上測試我發現由函數返回的const rvalue仍然通過移動構造函數發送。在C++ 14中有沒有指定這個的新東西,還是隻有編譯器特定的優化? – pikaille

1

您可能實際上遇到局部變量超出範圍的問題。

c_str()返回一個指向內部緩衝區的指針,所以一旦原始變量超出作用域,指針將會失效。

+0

我意識到這一點,但問題實際上是關於返回常量值。我猜即使使用r值引用,返回const值也會阻止移動。我以前認爲的一個好習慣突然是不正確的。 – zrb

-3

返回值的const限定符沒有語義含義。如果您在編譯器中調出警告級別,則每次執行此操作時都會發出警告。

+0

作爲一般性聲明,這是絕對不正確的。也許你可以澄清或提供一個你正在談論的具體內容的參考? – wjl