5

我正在测试这段代码,想知道为什么在编译时没有失败?我正在使用 c++11 和 g++ 4.7.2。

我的生产代码有类似的结构,它在运行时给出错误,然后我发现我正在用错误的参数类型构造类。

#include <iostream>
#include <vector>


typedef std::vector<std::string> Word;

class Data {
    public:
        const Word &word;
        Data(Word w) : word(w) {}
};

class Base{
    const Data &data;
    public:
        Base(const Data &d): data(d) {}
        ~Base() {}
};

class Work : public Base{
    public:
        Work(const Data &d): Base(d){}
        ~Work() {}
};


int main(int argc, char **argv){
    Word words;
    words.push_back("work");

    /*
    * I'm confused with this constructor, why this passed the compilation
    * ??
    * Any special rule to reason this scenario ??
    *
    * But obviously it will fail at run time.
    */
    const Work *work  = new Work(words);

    return 0;
}
4

3 回答 3

10

Data可从 构造Word,因此您可以将 a 传递WordWork构造函数。在幕后,Data将从传递的实例中创建一个实例,然后将其Word传递给构造函数。

Data您可以通过将其构造函数标记Word显式来避免这种情况,如下所示:

class Data {
    public:
        const Word &word;
        explicit Data(Word w) : word(w) {}
};

这样,构造函数就不能再被隐式应用了,Work除非你显式调用构造函数,否则你对构造函数的调用将无法编译Data

const Work *work  = new Work(words);        // Implicit call, fails to compile.
const Work *work  = new Work(Data(words));  // Explicit call, compiles.
于 2013-09-06T07:51:36.920 回答
5

可以编译*因为Data有一个带Word引用的隐式转换构造函数:

Data(Word w) : word(w) {}

这意味着您可以执行以下操作

Word words;
Data d1 = words;
Data d2(words);

你可以Work从一个Datavia 构造函数构造一个Work(const Data &d): Base(d){}

Work w(d2);

这意味着以下也是有效的,因为它只涉及一个用户定义的转换:

Work w2(words); // constructs Data temporary from words, then constructs w2 with it

可以通过将转换构造函数声明为explicit

explicit Data(Word w) : word(w) {}

*您实际上不起作用,因为它涉及对临时Data对象的悬空引用

于 2013-09-06T07:51:46.470 回答
2

以下构造函数退出后,word引用类型的数据成员将引用一个不再存在的对象:

class Data {
    public:
        const Word &word;
        Data(Word w) : word(w) {}
};

创建一个自动存储持续时间的变量来保存w。您将对该变量的引用存储为成员word,然后在构造函数退出时销毁裁判。

不管其他问题如何,我认为这不是你的意图。

于 2013-09-06T08:06:05.533 回答