C++ 通过引用返回和通过常量引用返回值被复制

Ste*_* B. 2 c++ return reference const-reference return-by-reference

我有一些关于重新获取类成员变量的引用的问题。

我有以下代码:

#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);
  }
};
Run Code Online (Sandbox Code Playgroud)
  1. 我注意到如果我这样做:

    std::set<uint32_t> returned = test.GetValues ();
    
    Run Code Online (Sandbox Code Playgroud)

    变量returned得到一个副本,而不是一个引用,为什么?

  2. const std::set<uint32_t> & GetValues () const函数是否必须包含双const精度值(返回值上的一个和函数名后的一个)?

编辑:其他问题:

  1. 知道这std::set<uint32_t> returned = test.GetValues ();会创建一个副本。如果我这样做:

    test.GetValues ().size ();
    
    Run Code Online (Sandbox Code Playgroud)

    为了调用size ()函数(或返回对象的任何其他成员),是临时创建副本还是使用返回的引用解析所有副本?

  2. 有三个函数,按值返回,按常量引用和按引用是不是很糟糕?

    // 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;
    }
    
    Run Code Online (Sandbox Code Playgroud)

Cur*_*ous 5

返回的变量得到一个副本,而不是一个引用,为什么?

例如,当您使用引用来初始化类型不是引用的值时,您将获得一个副本

#include <cassert>

int main() {
    int a = 1;
    const int& a_ref = a;
    int b = a_ref;
    assert(&b != &a);
}
Run Code Online (Sandbox Code Playgroud)

const std::set<uint32_t> & GetValues () const函数是否必须包含双常量

第二个 const 用作成员函数限定符,这意味着当您的类的调用实例为 const 限定时,可以调用该方法。例如

Test test;
test.GetValues(); // 1
const Test& test_ref = test;
test_ref.GetValues(); // 2
Run Code Online (Sandbox Code Playgroud)

这里1将调用非常量版本,2并将调用限定的方法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
Run Code Online (Sandbox Code Playgroud)

这里1是允许但2不允许的。

出现这种情况,如果你是好奇的原因,是因为隐式this指针const资格成为一个指向constconst合格的方法。


为了调用 size() 函数(或返回对象的任何其他成员),是临时创建的副本还是使用返回的引用解析所有内容?

size()方法将在引用上调用!测试此类事情的最佳方法是在快速测试用例https://wandbox.org/permlink/KGSOXDkQESc8ENPW 中进行尝试(请注意,我已经使测试比演示所需的要复杂一些)

有三个函数,按值返回,按常量引用和按引用是不是很糟糕?

如果您将用户暴露给可变引用,那么让他们制作副本(这就是您使用按值的原因)方法的最佳方法是让他们通过初始化set具有返回参考(就像你最初做的那样)

同样在您的代码中,以下两种方法之间存在歧义

std::set<uint32_t> GetValues() const
const std::set<uint32_t>& GetValues () const
Run Code Online (Sandbox Code Playgroud)

因为唯一不同的是返回类型,并且您不能在返回类型之外重载函数

  • @SteveB。NP!回答了您的新问题 (2认同)

Vla*_*cow 5

变量returned是一个单独的对象,必须有自己的值。

因此在这个声明中

std::set<uint32_t> returned = test.GetValues ();
Run Code Online (Sandbox Code Playgroud)

函数返回的引用所引用的值被复制到对象中returned

如果你声明一个引用而不是对象,例如

std::set<uint32_t> &returned = test.GetValues ();
Run Code Online (Sandbox Code Playgroud)

那么在这种情况下,引用returned将引用类对象的原始对象,并由函数返回的引用初始化。

至于第二个问题,则返回类型不参与重载函数解析。

因此,例如,如果您将删除第二个 const 限定符

const std::set<uint32_t> & GetValues ();
std::set<uint32_t> & GetValues (); 
Run Code Online (Sandbox Code Playgroud)

那么对于这样的调用,这两个函数之间存在歧义

std::set<uint32_t> returned = test.GetValues ();
Run Code Online (Sandbox Code Playgroud)