簡體   English   中英

將rvalue轉換為const指針是有效的C ++嗎?

[英]Is it valid C++ to cast an rvalue to a const pointer?

在急速的時刻,需要一個指向對象的指針傳遞給一個函數。 我拿了一個未命名的臨時對象的地址,令我驚訝的是它編譯了(原始代碼的警告進一步向下,缺少下面例子中的const正確性)。 好奇,我設置了一個受控制的環境,一直有警告,並將警告視為Visual Studio 2013中的錯誤。

請考慮以下代碼:

class Contrived {
  int something;
};

int main() {
  const Contrived &r  = Contrived();                    // this is well defined even in C++03, the object lives until r goes out of scope
  const Contrived *p1 = &r;                             // compiles fine, given the type of r this should be fine. But is it considering r was initialized with an rvalue?
  const Contrived *p2 = &(const Contrived&)Contrived(); // this is handy when calling functions, is it valid? It also compiles
  const int       *p3 = &(const int&)27;                // it works with PODs too, is it valid C++?

  return 0;
}

三個指針初始化都或多或少是相同的。 問題是,這些初始化是在C ++ 03,C ++ 11或兩者下有效的C ++嗎? 考慮到rvalue引用周圍的大量工作,我會分別考慮C ++ 11以防萬一。 分配這些值可能似乎不值得,例如在上面的示例中,但是值得注意的是,如果將這些值傳遞給采用常量指針的函數並且您沒有適當的對象並且感覺不到比如在上面一行上制作一個臨時對象。

編輯:
根據答案,上面是有效的C ++ 03和C ++ 11。 關於最終對象的生命周期,我想提出一些額外的澄清要點。

請考慮以下代碼:

class Contrived {
  int something;
} globalClass;
int globalPOD = 0;

template <typename T>
void SetGlobal(const T *p, T &global) {
  global = *p;
}

int main() {
  const int *p1 = &(const int&)27;
  SetGlobal<int>(p1, globalPOD);              // does *p still exist at the point of this call?

  SetGlobal<int>(&(const int&)27, globalPOD); // since the rvalue expression is cast to a reference at the call site does *p exist within SetGlobal

  // or similarly with a class
  const Contrived *p2 = &(const Contrived&)Contrived();
  SetGlobal<Contrived>(p2, globalClass);
  SetGlobal<Contrived>(&(const Contrived&)Contrived(), globalClass);

  return 0;
}

問題是對SetGlobal的調用中的一個或兩個是否有效,因為它們傳遞的指針指向在C ++ 03或C ++ 11標准下調用期間將存在的對象?

rvalue是一種表達式,而不是一種對象。 我們在談論由Contrived()創建的臨時對象 ,說“這個對象是一個右值”是沒有意義的。 創建對象的表達式是rvalue表達式,但這是不同的。

即使所討論的對象是臨時對象,其壽命也已延長。 使用表示它的標識符r對對象執行操作是完全正確的。 表達式r是左值。

p1 p2p3行上,引用的生命周期在該完整表達式的末尾結束,因此臨時對象的生命周期也在該點結束。 因此,在后續行中使用p2p3將是未定義的行為。 初始化表達式可以用作函數調用的參數,如果這是你的意思。

第一個是好的:表達式r實際上不是右值。

另外兩個在技術上也是有效的,但要注意指針在完整表達式的末尾(在分號處)變得懸空,並且任何使用它們的嘗試都會表現出未定義的行為。

雖然通過const&傳遞rval是完全合法的,但你必須知道你的代碼最終會在p2p3使用無效指針,因為它們指向的對象的生命周期結束了。

舉例來說,請考慮以下通常用於通過引用傳遞臨時代碼的代碼:

template<typename T>
void pass_by_ref(T const&);

可以使用左值或右值作為參數調用這樣的函數(通常是)。 在這個函數里面你可以明顯地參考你的參數 - 它只是對一個const對象的引用...你基本上在沒有函數幫助的情況下做同樣的事情。

事實上,在C ++ 11中,您可以更進一步,獲取一個指向臨時的非const指針:

template<typename T>
typename std::remove_reference<T>::type* example(T&& t)
{
    return &t;
}

請注意,如果使用左值調用此函數,則返回值指向的對象將仍然存在(因為其參數將變為typename remove_reference<T>::type& && typename remove_reference<T>::type& ,這是typename remove_reference<T>::type& ) 。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM