2010-02-25 16 views
3

是下面的代碼安全(它在DEBUG):問題有關的臨時破壞的確切時間C++

void takesPointer(const Type* v);//this function does read from v, it doesn't alter v in any way 
Type getValue(); 
... 
takesPointer(&getValue());//gives warning while compiling "not an lvalue" 
... 
Type tmp = getValue(); 
takesPointer(&tmp);//this is safe, and maybe I should just do it, instead of posting here 

如此 - 它是安全的嗎?我應該忘記它,並使用明確的tmp代碼?

但反正 - 我仍然有興趣,如果優化器能夠從這個調用返回到前殺死臨時:

takePointer(&getValue()) 

編輯: 謝謝大家! 不幸的是我不能改變函數「takesPointer」(它是一個庫的一部分),我只能將它包裝在一個函數「takesReference」中,它調用takesPointer函數 - 是否會消除副本,還是允許編譯器創建一個副本(「Type」是一個int-3x3-Matrix,所以它不會那麼糟糕,但仍然...)?

inline void takesReference(const Type& v){ takesPointer(&v); } 

關於銷燬時間:它會在「takePointer」RETURNS後還是在它被調用之後被銷燬?

+0

'Type'對象將在包含'takesReference'的表達式完成後被銷燬。 – 2015-01-29 01:43:03

回答

0

您可以將一個非const rvalue綁定到一個const引用左值,但是您將它綁定到一個const指針左值。

並且不,在調用takePointer()之前,優化器不能破壞getValue()的結果。

7

該標準禁止你做&getValue() - 正是因爲它不是左值。通常,如果允許此,則該函數調用所產生的臨時值將一直存在,直到外部函數返回並且整個表達式中的其他所有內容都已完成處理。這可以被稱爲「全表達結束後銷燬臨時工」,並確保類似下面的工作的事情如預期

// the temporary string is alive until the whole expression has been processed 
cout << string("hello"); 

編譯器爲您提供了診斷 - 這是所有標準要求的形成不良的代碼。例如,它不會強制編譯器中止編譯。但是,在診斷出代碼格式不正確後,編譯器可以做它想做的一切。所以如果你想知道編譯器在你的情況下做什麼,你應該閱讀它的手冊。

1

這將防止副本*和編譯。

const Type& tmp = getValue(); 
takesPointer(&tmp); 

防止副本有點強壯,因爲編譯器經常會爲你做這件事。 你必須可以訪問拷貝構造函數,但編譯器通常不會使用它:

#include "iostream" 
class Type 
{ 
public: 
    explicit Type(int val) : m_val(val) { std::cout << "ctor";}; 
    Type(const Type& copy) 
    { 
     std::cout << "copy"; 
    }; 
private: 
    int m_val; 
}; 

Type getValue() { Type r(0); return r;}; 
void takesPointer(const Type* const) 
{ 

}; 

int main(int argc, char* argv[]) 
{ 
    const Type tmp = getValue(); 
    takesPointer(&tmp); 
} 

將在調試打印僅釋放「構造函數」和「ctorcopy」。 (MVS2005)

+0

不要竊取你的雷霆,所以你可能想提一下它爲什麼可以工作! – 2010-02-25 14:33:22

+1

「這將防止副本」 - 它不會。編譯器仍然可以創建副本。 – 2010-02-25 15:21:29

+0

感謝馬丁。將一個const引用存儲到一個對象將維持該函數結果的有效期,直到該引用超出範圍。 – 2010-02-26 09:57:42

10

正如其他答案已經聲明,你不能採取臨時地址。但是,如果你改變

void takesPointer(const Type* v); 

的簽名

void takesPointer(const Type& v); 

然後將下面的代碼應編譯沒有警告:

takesPointer(getValue()); 

,因爲你被允許綁定一個臨時的常量參考,它應該工作一樣。

+0

+1好點:) – 2010-02-25 15:21:49

0

是的,這是安全的,雖然目前的形式是非法的。您可以通過使用一個明確的中間鑄爲const引用類型

takesPointer(&(const Type &) getValue()); 

這使得只要臨時對象是活的,這是直到充分表達的評價到底是完全合法的解決該錯誤。此外,你甚至可以拋出const並通過指針修改臨時對象(記住它將在完整表達式的末尾被銷燬)。只要臨時對象本身不是常量,這是完全合法的。

使用逗號操作符,你可以在「拉伸」充分表達,因而寫了「長壽命」的臨時目標工作業務相當廣泛序列

Type *p; 
p = &(Type &) (const Type &) getValue(), modify(p), print(p), modifyAgain(p), print(p); 
// Not using C++ casts for brevity 

的做法是相當值得懷疑,但並大多數情況下,這樣做沒有意義。

+0

「此外,你可以甚至丟棄const並通過指針修改臨時對象「 - 遺憾的是,在C++ 03中不允許,因爲允許編譯器創建臨時副本並將引用綁定到該副本。如果存在,則需要創建一個'const Type'類型的副本(即cv-qualifiers來自引用,類型來自臨時文件。標準中有一個明確的'[sic]')。 – 2010-02-25 15:20:12

+0

@litb:感謝您的更正。我想知道這一段時間的合法性。 – AnT 2010-02-25 16:55:00