2017-06-30 90 views
1

我有一些關於returing類成員變量引用的問題。C++通過引用返回並通過const引用值返回被複制

我有以下代碼:

#include <stdint.h> 
#include <string> 
#include <iostream> 
#include <set> 

void 
PrintSet (const std::string & str, const std::set<uint32_t> & to_print) 
{ 
    std::cout << str << " (" << to_print.size() << "): "; 

    for (std::set<uint32_t>::const_iterator it = to_print.begin(); 
      it != to_print.end(); ++it) 
    { 
     std::cout << *it << " "; 
    } 

    std::cout << "\n"; 
} 

class Test 
{ 
private: 
    std::set<uint32_t> m_values; 

public: 

    Test() : m_values() { } 

    void 
    SetValues (const std::set<uint32_t> & values) 
    { 
    m_values = values; 
    } 

    const std::set<uint32_t> & 
    GetValues() const 
    { 
    return m_values; 
    } 

    std::set<uint32_t> & 
    GetValues() 
    { 
    return m_values; 
    } 

    void 
    Print() const 
    { 
    PrintSet ("TestInst", m_values); 
    } 
}; 
  1. 我注意到,如果我這樣做:

    std::set<uint32_t> returned = test.GetValues(); 
    

    變量returned得到一個副本,而不是一個參考,爲什麼呢?

  2. 是否const std::set<uint32_t> & GetValues() const功能必須包含雙const(一個在返回值和函數名後的)?

編輯:其他問題:

  • 明知std::set<uint32_t> returned = test.GetValues();創建一個副本。如果我這樣做:

    test.GetValues().size(); 
    

    爲了調用size()函數(或返回對象的任何其他成員),是一份臨時創建或全部與返回的參考解決?

  • 有三個函數,通過const引用和通過引用返回值是不是很糟糕?

    // Return by value 
    std::set<uint32_t> 
    GetValues() const 
    { 
        return m_values; 
    } 
    
    // Return by const-reference 
    const std::set<uint32_t> & 
    GetValues() const 
    { 
        return m_values; 
    } 
    
    // Return by reference 
    std::set<uint32_t> & 
    GetValues() 
    { 
        return m_values; 
    } 
    
  • +1

    的副本不會在發生調用這兩個函數之間的歧義返回按引用;該副本是因爲「返回」不是參考。 – user2357112

    +0

    'returned'不是引用,因爲你自己明確聲明它是'std :: set ',這不是引用。 – AnT

    回答

    3

    返回的變量得到一個副本,而不是一個參考,爲什麼呢?

    當您使用引用來初始化其類型是不是你得到一個拷貝的參考值,例如

    #include <cassert> 
    
    int main() { 
        int a = 1; 
        const int& a_ref = a; 
        int b = a_ref; 
        assert(&b != &a); 
    } 
    

    是否const std::set<uint32_t> & GetValues() const功能必須包含雙常量

    第二個const作爲成員函數限定符應用,這意味着可以在您的類的調用實例爲const限定時調用該方法。例如

    Test test; 
    test.GetValues(); // 1 
    const Test& test_ref = test; 
    test_ref.GetValues(); // 2 
    

    這裏1會調用非const版本,2將調用資格進行const

    方法進一步const限定的方法絕對不會讓你回到它自己的價值非const引用,因此您必須將const引用返回給您的成員變量m_values

    所以,如果你有第二const則必須包括第一const,但是如果你只是把返回類型是const參考,那麼你並不需要使該方法const。例如

    const std::set<uint32_t>& GetValues() // 1 
    std::set<uint32_t>& GetValues() { return m_values; } // 2 
    

    這裏1是允許的,但2是不允許的。

    出現這種情況,如果你是好奇的原因,是因爲隱含this指針const資格在const合格方法指針const


    爲了調用大小()函數(或返回的對象的任何其他部件),是複製臨時創建或全部與返回參考解決?

    size()方法將被調用的參考!測試這樣的事情最好的辦法是嘗試一下,在一個快速測試用例https://wandbox.org/permlink/KGSOXDkQESc8ENPW(請注意,我已經做了試驗一點比更復雜的只是爲了演示需要)

    做不好有三個功能,通過值返回,通過const引用和引用?

    如果將用戶暴露於可變引用,然後讓他們做一個副本(這就是爲什麼你有按值)的方法是讓他們做一份自己被初始化的最佳方式非裁判資格set與返回的引用(像你這樣開始)

    另外,在你的代碼中有

    std::set<uint32_t> GetValues() const 
    const std::set<uint32_t>& GetValues() const 
    

    以下兩種方法之間的上午歧義因爲所有不同的是返回類型,and you cannot overload a function off the return type

    +0

    感謝您提供快速詳細的答案。我剛剛在原文中增加了兩個問題(第3和第4)。如果你可以回答他們。 –

    +2

    @SteveB。 NP!回答你的新問題 – Curious

    3

    變量returned是一個單獨的對象,必須有它自己的值。

    在此聲明

    std::set<uint32_t> returned = test.GetValues(); 
    

    由該函數返回的引用所引用的值

    因此被複制到對象returned

    如果代替對象聲明一個參考,例如

    std::set<uint32_t> &returned = test.GetValues(); 
    

    那麼在這種情況下,參考returned將引用類對象的原始對象,並通過由該函數返回的引用初始化。

    至於第二個問題,那麼返回的類型不參與重載的函數解析。

    因此,舉例來說,如果你將下降的第二const限定符

    const std::set<uint32_t> & GetValues(); 
    std::set<uint32_t> & GetValues(); 
    

    再有就是像這樣

    std::set<uint32_t> returned = test.GetValues();