c ++构造函数的奇怪行为

时间:2013-09-06 07:48:24

标签: c++ c++11

我正在测试这段代码并想知道为什么在编译时没有失败?我正在使用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;
}

3 个答案:

答案 0 :(得分:10)

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

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

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.

答案 1 :(得分:5)

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

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

这意味着你可以做一些事情,比如

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

您可以通过构造函数WorkData构建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对象的悬空引用

答案 2 :(得分:2)

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

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

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

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