当我正在阅读我的c ++书并编写一些示例时,我想到了一个问题。
...
private:
const string someString;
public:
MyClass(const string& someString) : someString(someString) {}
const string& getSomeString() const { return someString; }
...
将someString声明为参考实际上是否有所不同?
...
private:
const string& someString;
public:
MyClass(const string& someString) : someString(someString) {}
const string& getSomeString() const { return someString; }
...
如果是这样,有什么优点/缺点或用例(因为这两个例子编译得很好)?
答案 0 :(得分:4)
后者很容易导致悬挂引用,因为它只是指向一些不受你的类控制的对象。所以我会避免这种情况。 (一如既往,除非你有充分的理由。)
另外一个显着的区别:在第二种情况下,你班级中的字符串"将改变"如果用于构造它的字符串确实如此,因为您只是引用它。在第一种情况下不会发生这种情况,因为您拥有自己的字符串副本。
答案 1 :(得分:3)
如果您想要自己的字符串,请不要存储对其他人字符串的引用。
在第二种情况下,您存储引用的字符串的生命周期必须超过您将其存储在的对象的生命周期。
例如,
MyClass instance("bad");
会在会员中留下悬空参考。
你在远处也有一个不那么致命但令人困惑的幽灵行动:
std::string s = "Hello";
MyClass instance(s);
s = "World";
std::cout << instance.getSomeString(); // Prints 'World'
根据我的经验,参考成员很少是一个好的解决方案。
答案 2 :(得分:1)
构造函数中引用的字符串来自类外部。只要原始字符串有效,引用成员才有效。考虑这个例子:
MyClass *p;
{
string temp = "hello";
p = new MyClass(temp);
}
cout << p->getSomeString(); // reference to destroyed object
此代码错误,因为类中引用的字符串temp
不再存在。
这个问题可以更加巧妙地表现出来。
const char *text = "Hello";
MyClass c(text);
cout << c.getSomeString(); // reference to destroyed object
此代码也是错误的,因为在下一行的时间内,为构造函数调用创建的临时std::string
对象不再存在。
答案 3 :(得分:1)
如果您将someString
声明为const string
,它将包含在构造函数中传递给它的值。
然而,someString
是const string&
,它保存了一个字符串的地址,该字符串存储在类之外的某个地方,该类无法保证在任何时候都存在在将来,你应该避免这个。
答案 4 :(得分:0)
如果someString
不应该是观察者,那么通过存储引用,你意味着错误的语义。我会避免这种情况。
Otoh,如果它应该是一个观察者,那么你显然必须存储一个参考。