C ++引用类型推荐用法

时间:2009-09-26 13:30:54

标签: c++ reference

我用C ++编程超过5年,并且从未遇到任何建议使用变量引用的地方,除非作为函数参数(如果你不想复制你传递的函数参数) 。那么有人可能会指出使用C ++变量引用的情况(我的意思是它有任何优势)。

13 个答案:

答案 0 :(得分:16)

作为不透明集合访问者/ mutator的返回值

operator[]的{​​{1}}会返回引用。


缩短引用变量所需的文字

如果您错过了老式std::map语句(那是Pascal语法),您可以写

with Foo do ...

另一个例子可以在Mike Dunlavey's answer

中找到

说明某些内容只是一个参考

引用在包装器对象和仿函数中也很有用 - 即。在中间对象中,逻辑上不接触任何成员,只接触引用

示例:

 MyString &name = a->very->long_->accessor->to->member;
 if (name.upcase() == "JOHN") {
    name += " Smith";
 }

如果你没有在这样一个对象的构造函数中初始化引用,那么这是一个编译错误的想法。编译时检查越多 - 程序越好。

答案 1 :(得分:11)

这是一个方便的案例:

MyClass myArray[N];

for (int i = 0; i < N; i++){
    MyClass& a = myArray[i];
    // in code here, use a instead of myArray[i], i.e.
    a.Member = Value;
}

答案 2 :(得分:8)

在你想要的任何地方使用引用,当你被迫时使用指针。

引用和指针共享其语义的一部分:它们是不存在的元素的别名。主要区别在于内存管理:引用清楚地表明您不对资源负责。另一方面,使用指针它永远不会清楚(除非你的意思是智能指针):你是假设删除指针还是外部删除?

必须使用指针,必须管理内存,想要允许可选语义或需要更改稍后引用的元素。

在其他情况下,您可以使用引用或指针,引用更清晰,应该是首选。

现在,正如你所指出的,它们实际上并不需要:你总是可以使用指针进行所有的参考使用(甚至是参数传递),但是你可以使用单一工具来处理所有事情并不意味着没有更适合工作的工具。

答案 3 :(得分:5)

我倾向于使用引用成员而不是外部控制的非可选构造参数的指针。

编辑(添加示例):

假设您有一个数据库和一个将数据库作为依赖项的DAO类:

struct Database {};
struct PersonDao {
    const Database &m_d;
    PersonDao(const Database &d): m_d(d) {}
};

此外,数据库的范围由DAO外部控制:

int main() {
    Database d;
    PersonDao pd(d);
}   

在这种情况下,使用引用类型是有意义的,因为你不希望DAO :: m_d为null,并且它的生命周期是在外部控制的(在这种情况下来自main函数)。

答案 4 :(得分:3)

我在函数参数中使用引用不仅仅是为了避免复制而是使用指针来避免必须在适当的地方处理NULL指针。指针模型“可能有一个值,但可能不是(NULL)”,引用是一个明确的声明,表明需要一个值。

...并使其绝对清晰( - &gt;评论)。我倾向于避免指向模型的指针“也许有几个值” - 向量是一个更好的选择。指向多个值的指针通常最终会出现在C风格的编程中,因为您通常也必须单独传递元素数。

答案 5 :(得分:3)

使用const引用为值赋予名称,例如:

const Vec3 &ba=b-a;

这会为该值命名,但不一定会为其创建变量。理论上,这为编译器提供了更多的余地,并且可以允许它避免一些复制构造函数调用。

Const reference to temporary处的相关非重复堆栈溢出问题.Herb Sutter链接有更多相关信息。)

答案 6 :(得分:3)

复制构造函数的参数必须作为引用传递,否则复制构造函数需要在无限递归中调用它(堆栈溢出)。

答案 7 :(得分:1)

我倾向于同意,但也许是const返回值。

答案 8 :(得分:1)

你有两种选择来别名其他值(忽略shared_ptrs等):指针和引用。

必须在构造时初始化引用以引用其他内容。从语义上讲,引用永远不能为NULL。但实际上,基础数据可能会消失,给你的问题通常比指针消失时更难调试。所以我不确定这里有什么真正的优势,除非你受到纪律处分,并且与他们如何被用来引用动态分配的项目相一致。如果你也用指针做了这个,你就可以避免同样的问题。

也许更重要的是,可以在不考虑指针出现的所有问题的情况下使用引用。这可能是主要优势。在语义上,引用的东西。如果你保证作为调用者/被调用者的底层内存不会消失,你不必将用户与指针附带的任何问题混淆(我是否需要释放它?这可能是NULL吗?等)并且可以安全地使用参考文献。

这个例子可能是一个查找枚举对应字符串的函数,

const std::string& ConvertToString( someEnum val)
{
   static std::vector< std::string > lookupTable;
   if (lookupTable.empty())
   {
      // fill in lookup table
   }
   // ignoring the cast that would need to happen
   return lookupTable[val]
}

这里调用者和被调用者之间的契约保证返回类型将始终存在。您可以安全地返回引用,并避免指针邀请的一些问题。

答案 9 :(得分:1)

引用使代码更漂亮。因此,每当它引用美化代码时都要使用它们。

答案 10 :(得分:1)

流操作符是一个明显的例子

std::ostream & operator<< (std::ostream &, MyClass const &...) {
  ....
}

mystream << myClassVariable;

你显然不希望指针因为检查NULL而使得运算符非常繁琐i.s.o.方便

答案 11 :(得分:0)

我想提出一些案例:

编写单例类

时,

1)

 class singleton
    {
        singleton();
        explicit singleton(const singleton&);
        singleton& operator=(const singleton&);
    public:
        static singleton& instance()
        {
            static singleton inst;
            return inst;
        }
    };// this is called the 'Meyers' singleton pattern. refer to More Effective C++ by  Scott Meyers

它具有所有好处,但避免使用新的运算符

** 2)**这里没有空引用。引用必须始终引用某个对象。因此,如果您的变量的目的是引用另一个对象,但可能没有要引用的对象,则应该将该变量设为指针,因为这样您就可以将其设置为null。另一方面,如果变量必须始终引用一个对象,即,如果您的设计不允许该变量为null,则应该将该变量作为引用

** 3)**因为引用必须引用一个对象,所以C ++要求初始化引用:

  string& rs;             // error! References must
                          // be initialized

  string s("xyzzy");

  string& rs = s;         // okay, rs refers to s

Pointers are subject to no such restriction

没有空引用这样的事实意味着使用引用比使用指针更有效。那是因为在使用它之前不需要测试参考的有效性

** 4)**指针和引用之间的另一个重要区别是指针可能会被重新分配以引用不同的对象。但是,引用始终指的是初始化它的对象:¤项目M1,P10

  string s1("Nancy");
  string s2("Clancy");

  string& rs = s1;         // rs refers to s1

  string *ps = &s1;        // ps points to s1

  rs = s2;                 // rs still refers to s1,
                           // but s1's value is now
                           // "Clancy"

  ps = &s2;                // ps now points to s2;
                           // s1 is unchanged

答案 12 :(得分:0)

我使用了对ostream的引用而不是指针。我认为当类有很多运算符时,我更喜欢引用指针。