2013-03-18 81 views
4

爲什麼賦值運算符被允許返回void?爲什麼在這種情況下分配鏈接起作用?看看代碼,我將會非常清楚我在說什麼。重載賦值運算符而沒有返回語句

代碼:

struct Foo 
{ 
    std::string str; 

    Foo(const std::string& _str) 
    : str(_str) 
    { 
    } 

    Foo& operator=(const Foo& _foo) 
    {  
     str = _foo.str; 
     //return *this; /* NO RETURN! */ 
    } 
}; 

int main() 
{ 
    Foo f1("1"); 
    Foo f2("2"); 
    Foo f3("3"); 
    f1 = f2 = f3 = Foo("4"); 

    std::cout << "f1: " << f1.str << std::endl; 
    std::cout << "f2: " << f2.str << std::endl; 
    std::cout << "f3: " << f3.str << std::endl; 

    return 0; 
} 

問題:

  1. 爲什麼這是合法的嗎? (爲什麼會編譯)
  2. 它爲什麼會起作用?

我讀過很多地方「賦值運算符應返回* ,這樣你可以有任務鏈」,這完全是有道理的,但後來爲什麼上面的工作?

試試看:
online c++ workspace with the code from above

+0

它返回'美孚&','不void'。 – vines 2013-03-18 10:35:01

回答

7

爲什麼這是合法的嗎? (爲什麼它編譯所有)

這是法律,並注入在你的程序未定義行爲。你的編譯器至少應該警告你(如果你設置了足夠高的警告級別,我相信它會這樣做)。

每個段落的C++ 11標準的6.6.3/2:

流動關閉的功能的端部是相當於沒有值的返回; 這會導致在返回值函數中出現未定義的 行爲。

唯一的例外是main()函數,該函數允許缺少return語句。每個段落3.6.1/5:

的return語句在main具有離開main功能(破壞用自動 存儲持續時間的任何對象),並調用std::exit與返回值作爲參數的效果。 如果控制到達終點的main 沒有遇到return語句,其效果是執行的

return 0; 

最後:

爲什麼它的工作?

未定義行爲意味着您的程序可能在某些機器上運行,但不在其他機器上運行;或者它可能在今天的所有機器上運行,但不是明天;否則會導致你的程序出現一些奇怪的,不可預知的結果;包括(這是最差的的情況)似乎運行得很好。

+0

任何想法,爲什麼這不是一個編譯器錯誤? – Dario 2013-03-18 10:37:12

+0

@達里奧:不,我不知道。也許出於兼容性原因。也許這在過去有時是允許的,編譯器仍然可以編譯遺留代碼。這只是一個猜想。我不知道C中是否允許這樣做,但這可能是另一個原因。無論如何,這在C++中絕對是非法的,除了'main()'函數。 – 2013-03-18 10:39:05

+0

@Dario - 對於無效代碼,C++標準要求實現問題「診斷」。唯一需要不編譯的東西是'#error'指令。然而,當某些東西產生未定義的行爲時,它只是意味着標準沒有說明會發生什麼;這就是這種情況。在這種情況下的原因是在更復雜的情況下很難診斷。有些情況下,一個編譯器不會注意到這個錯誤,另一個編譯器會這麼做;但是有一個小小的改變,反過來也是如此。 – 2013-03-18 12:30:57

2

你有什麼是未定義的行爲,因爲你正在流失一個函數的結尾,承諾會返回一些東西。

在C++中執行此操作的唯一函數是int main()(以及帶參數的版本),因爲它在沒有返回語句的情況下隱式返回0

0

檢查編譯後產生的asm代碼。我的猜測是這個函數返回寄存器AX中發生的情況(如果我沒有弄錯,這是c調用標準函數實現)。在你的情況下,它恰好是你想要它...如果你添加一些功能的功能,你可能會打破它...

0

它的非法,如果它編譯然後以一種方式它存儲的東西運行時很奇怪。你必須從這個函數返回* this。正確的函數定義看起來像

Foo& operator=(const Foo& _foo) 
{  
    if(this == &_foo) /* check for self-assignment */ 
    return *this; 

    str = _foo.str; 

    return *this; 
} 

返回*,這是必須的連鎖任務像

Foo x, y, z; 
x = y = z;  /* *this is necessary for this statement */