我刚刚意识到我甚至无法弄清楚C ++中引用成员的一个用例。比如说,如果我定义以下类:
class Book {
public:
Book(const Author& author) : author(author) {}
private:
const Author &author;
}
我怎么能用呢?如果我将new
ed Author
传递给它:
Book book(*(new Author()));
它不会泄漏内存吗? Author
什么时候会被释放?
让我再试一次。如何将局部变量传递给它:
Book macBook() {
Author author();
return Book(author);
}
返回的图书是否包含无效(已发布)参考?
我无法想象使用它的第三种方式。那么为什么参考成员存在?我什么时候应该使用它?
编辑:我知道有share_ptr
。但我是否总是希望share_ptr
参考?
答案 0 :(得分:3)
你必须确保作者的一生至少和书一样长(或者至少要小心不要在作者的一生之外使用本书的参考)。确保这一点的一种简单方法是将它们放在同一范围内,首先创建作者:
Author author;
Book book(author);
正如你所说,问题中的两个例子都很糟糕:第一个泄漏内存(或者,如果你添加了一个*
来进行编译),第二个会给你一个悬空引用。但是还有很多其他方法来管理对象的生命周期。
答案 1 :(得分:2)
如果您的功能需要const Author&
并且您传递new Author()
,那么您的程序将无法编译,因为new Author()
是Author*
,而不是Author&
}。
您可以传递*(new Author())
,但除非Book
的析构函数删除&author
,否则您将会泄密。但是,拥有一个引用成员并在析构函数中获取该成员的地址并delete
它是非常奇怪的。你的开发人员会讨厌你,尤其是因为函数签名不清楚,必须使用new
来分配参数。
您可以将Author
传递给Book(const Author& author)
,但必须确保Author
至少和Book
一样长。是的,在代码中
Book macBook() {
Author author();
return Book(author);
}
退回的图书无效参考。
我怀疑引用成员存在的原因与存在空指针的原因相同:因为它很容易实现。
答案 2 :(得分:1)
如果按值复制对象的代价很高,则通常引用很有用。如果将对象作为参数传递给函数,并且复制它的代价很高,则需要使用引用。当然,如果您不打算通过函数修改对象,您实际上将使用常量引用:
void someFunc(const BigObject& object)
{
/* 'object' is used here */
}
现在一个类构造函数是“只是另一个函数”,所以我们可以在这里使用相同的模式:如果你想提供一个复制到某个类实例的昂贵的对象,以便在其生命周期内使用 ,在该类中定义一个const-ref成员是有意义的,该成员将绑定到类构造函数中提供的对象:
class Worker
{
public:
Worker(const BigObject& object) : m_object(object) { /* ... */ }
// ...
private:
const BigObject& m_object;
}
BigObject object;
Worker worker(object);
当然,这里要记住的最重要的事情是确保BigObject
对象存在时Worker
对象不会被销毁。 (在上面的示例中,这是正常的,因为两个变量都是自动的。)
当然,可以使用指针代替引用来实现相同的效果,但是使用指针时,总是必须考虑指针为零(有意或无意)的情况,并且需要明确使用{ {1}}运算符传递对象,因此引用版本只是使代码更简单。