2011-04-28 71 views
2

下面的代碼如何禁止在C++ 2011中調用右值對象的const成員函數?

#include <vector> 
#include <string> 
#include <iostream> 

std::string const& at(std::vector<std::string> const& n, int i) 
{ 
    return n[i]; 
} 

std::vector<std::string> mkvec() 
{ 
    std::vector<std::string> n; 
    n.push_back("kagami"); 
    n.push_back("misao"); 
    return n; 
} 

int main() 
{ 
    std::string const& s = at(mkvec(), 0); 
    std::cout << s << std::endl; // D'oh! 
    return 0; 
} 

可能導致崩潰,因爲原來的載體已經被破壞那裏。右值參考被引入在C++ 2011(C++ 0X)之後,一個刪除功能聲明可以用來如果向量參數是一個rvalue

std::string const& at(std::vector<std::string>&&, int) = delete; 

這看起來好完全禁止向at呼叫,但下面的代碼仍然會造成碰撞

int main() 
{ 
    std::string const& s = mkvec()[0]; 
    std::cout << s << std::endl; // D'oh! 
    return 0; 
} 

因爲到右值對象的成員函數調用operator [] (size_type) const仍允許。有什麼辦法可以禁止這種呼叫嗎?

FIX:

上面的例子是不是我在實際項目中做到了。我只是想知道C++ 2011支持任何成員函數資格像

class A { 
    void func() rvalue; // Then a call on an rvalue object goes to this overload 
    void func() const; 
}; 

FIX:

這是偉大的,但我認爲C++標準走得太遠,在此功能。不管怎麼說,我有以下的代碼編譯上鐺++ 2.9

#include <cstdio> 

struct A { 
    A() {} 

    void func() & 
    { 
     puts("a"); 
    } 

    void func() && 
    { 
     puts("b"); 
    } 

    void func() const & 
    { 
     puts("c"); 
    } 
}; 

int main() 
{ 
    A().func(); 
    A a; 
    a.func(); 
    A const b; 
    b.func(); 
    return 0; 
} 

非常感謝!

回答

6

不,你不應該。我該怎麼做std::cout << at(mkvec(), 0) << std::endl;,如果你禁止我在臨時使用at(),這是一件完全合理的事情?

不幸的是,存儲臨時對象的引用只是一個問題,C++程序員必須處理。


要回答你的新問題,是的,你可以這樣做:

class A { 
    void func() &; // lvalues go to this one 
    void func() &&; // rvalues go to this one 
}; 

A a; 
a.func(); // first overload 

A().func(); // second overload 
+0

我我總是發現這個參考綁定令人震驚。開始的時候一定是個好主意,有時候確實很方便,但是它的破壞潛力是不可思議的,甚至仔細的代碼檢查可能無法檢測到它...:/ – 2011-04-28 06:36:55

+0

感謝你的提示,但我得到了編譯g ++ 4.6.0上的錯誤。你能告訴我哪個編譯器可以處理嗎? – neuront 2011-04-28 07:41:14

+0

如果你將'func'重載公開,那麼clang的最近版本將處理這個例子。 – 2011-04-28 13:29:06

-1

只是一個想法:

要禁用向量複製構造莫名其妙。

vector (const vector<T,Allocator>& x); 

無論如何,隱式拷貝數組並不是件好事。 (不知道爲什麼STL作者決定來定義所有這些構造函數)

,就像你提到的它會解決問題,並作爲獎勵會強迫你使用更有效的版本的功能:

void mkvec(std::vector<std::string>& n) 
{ 
    n.push_back("kagami"); 
    n.push_back("misao"); 
} 
+1

你是否認真地建議他修改他的標準庫來使得矢量不可複製?還是我誤讀你?因爲這是我聽過的最蠢的建議。 – 2011-04-28 03:33:37

+1

您的'mkvec'版本不一定更高效,查找RVO。 – GManNickG 2011-04-28 04:17:57

+0

函數'mkvec()'很好,是的!感謝** Return-Value-Optimization **,以及C++ 0x甚至更多,感謝RValues,是的。是的,寫這樣的代碼,它是RAII,簡潔,安全和快速。但是,當然'string&s = mkvec()[0]'爆炸了,那是正確的。你把它命名爲'mk ...'**製造**。不要在你剛剛*做的東西上得到一個參考* - 這是問題。如果你將它稱爲'getvec()',*然後*我希望'string&s = getvec()[0]'是可以的。但'string&s = mkvec()[0]'被允許失敗:-) – towi 2011-04-28 19:16:08