引用变量出现错误,必须在构造函数的基础/成员初始化器中进行初始化。

5

当我尝试编译下面的源代码时,遇到了以下错误。有没有人能说明为什么会出现这个错误以及如何修复它呢?

错误 1 错误 C2758: 'A::s_' : 必须在构造函数基类/成员初始化程序中初始化

#include <iostream>
#include <string>

using namespace std;

class A
{
public:
    A(string& s) : s_(s) { cout << "A::ctor" << endl; }
    A(const A& rhs)      { cout << "A::copy" << endl; }
    ~A()                 { cout << "A::dtor" << endl; }

    A& operator=(const A& rhs) { cout << "A::copyassign" << endl; }

private:
    string& s_;    
};

int main()
{

    return 0;
}

1
当你有一个引用成员时,你实际上无法拥有一个语义上有效的赋值运算符。你不能将其重新分配给不同的字符串。它只会修改被引用的原始字符串。 - Peter Wood
3个回答

12

首先,你的A::s_是一个指向std::string的引用;这意味着它引用了某个必须存在的东西。

由于它是引用类型,并且引用在创建时必须进行初始化,你必须在所有的A构造函数中初始化A::s_(正如其他用户所指出的那样):

class A
{
public:
    A(string& s) : s_(s)
    { cout << "A::ctor" << endl; }

    A(const A& rhs) : s_(rhs.s_) // <-- here too!!
    { cout << "A::copy" << endl; }

    ~A()
    { cout << "A::dtor" << endl; }

    A& operator=(const A& rhs)
    { cout << "A::copyassign" << endl; }

private:
    string& s_;    
};

现在回到我提到的第一个问题;A::s_必须引用存在的内容,因此您必须了解一些事情,请看下面的代码:

int main()
{
    // New A instance:
    A a("hello world");

    return 0;
}
构造这个实例时,我们提供一个const char[12]值,使用该值创建了一个临时的std::string并将其提供给A::A(string& s)构造函数。当构造函数结束后,A::s_引用的是什么?这个临时的std::string会发生什么?它的生命周期是否延长,还是在构造函数结束时就消失了?你确定需要引用吗?
std::string s("hello world");

int main()
{
    // New A instance:
    A a(s);

    return 0;
}

使用上面的代码,创建了一个新的A实例,调用相同的A::A(string& s)构造函数,但提供的字符串位于全局作用域中,因此它不会被销毁,a实例中的A::s_将在其整个生命周期内引用有效的字符串,但真正的威胁在于复制构造函数:

std::string s("hello world");

int main()
{
    A a(s);    // a.s_ references the global s.
    A b(a);    // b.s_ references the a.s_ that references the global s.

    return 0;
}

复制的对象值将引用给定对象的 std::string!这是你想要的吗?


非常感谢您提供的详细说明。 - Number42
1
我只想指出,你一开始就不能把“hello world”传递给它(即编译器错误),因为临时变量无法绑定到非常量引用。 - chris
@chris 它对我有效。在A a("hello world")调用时创建的临时对象被绑定到a.s_引用。 - PaperBirdMaster
我的错!你是对的!我太傻了!:( 这证明把std::string引用作为成员并且使用非显式构造函数甚至比我想象的更糟糕! - PaperBirdMaster

2

你的复制构造函数从未初始化该引用。请确保它进行初始化:

A(const A &rhs) : s_(rhs.s_) {cout << "A::copy" << endl;}

0
 string& s_;

这是一个引用变量。由于它是对象的一部分,因此在对象分配时应该有一个值,这就是为什么应该使用构造函数的初始化列表来初始化此属性的原因。
如果您不需要将此属性视为对象的一部分,则可以使用指针代替引用:
 string* s_;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接