2017-06-30 62 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();