【问题标题】:Pointer initialization to different class in constructor c++指向构造函数c ++中不同类的指针初始化
【发布时间】:2015-08-13 12:54:08
【问题描述】:

我在 BirdHouse 的构造函数初始化列表中初始化指向 Bird 的指针时遇到问题。好像没有指向我要指向的对象。

这是 Bird 类:

class Bird
{
    std::string name;
    static int objectCount;
public:
    Bird () : name("Bird #" + std::to_string(objectCount))
    {
        ++objectCount;
    }

    Bird (const Bird& bb) : name(bb.name + " copy")
    {
    }

    friend class BirdHouse;
};

这里是 BirdHouse 类:

class BirdHouse
{
    Bird b;
    Bird * bp;
    Bird & br;
public:
    BirdHouse(Bird aa, Bird bb, Bird cc) : b(aa), bp(&bb), br(cc) {}

    void print() const
    {
        std::cout << "Bird b = " << b.name << std::endl;
        std::cout << "Bird * bp = " << bp->name << std::endl;
        std::cout << "Bird & br = " << br.name << std::endl;
    }
};

当我想在 main() 中调用 BirdHouse::print() 时,程序崩溃:

int main()
{
    Bird b1;
    Bird b2;
    Bird b3 = b2;

    BirdHouse bh1(b1,b2,b3);
//    bh1.print();    // I can't call it because b2 points to weird stuff

    return 0;
}

我应该如何初始化 BirdHouse 对象,使其指向合适的 Bird 对象?

【问题讨论】:

    标签: c++ pointers initializer-list


    【解决方案1】:

    崩溃是由于未定义的行为,因为您保存了指向按值传递的参数的指针,并且该对象将在函数返回后被破坏。

    我可以看到有两种可能的解决方案:要么将变量作为指针传递,要么通过引用传递。但是,请小心,因为如果 BirdHouse 对象的生命周期长于您传入的对象(作为指针或引用)的生命周期,您将再次出现未定义的行为。

    【讨论】:

      【解决方案2】:
      BirdHouse(Bird aa, Bird bb, Bird cc) : b(aa), bp(&bb), br(cc) {}
      

      aabbcc 是按值传递的参数,它们是构造函数的本地参数。但是,您存储了一个指向 bb 的指针和一个对 cc 的引用,当构造函数结束时,它们都会变得悬空。

      当您尝试访问 print() 中的悬空成员之一时,您会触发未定义的行为,在您的情况下是崩溃。不要那样做。

      打开你的编译器警告可能会通知你这个问题。

      【讨论】:

        【解决方案3】:
        BirdHouse(Bird aa, Bird bb, Bird cc) : b(aa), bp(&bb), br(cc) {}
        

        在这里,您按值获取参数,从而创建一个副本。然后,您继续存储一个指针和对这些副本的引用,这些副本将在构造函数的末尾被破坏。现在,每当您尝试访问这些时,都会调用未定义的行为。

        要解决此问题,您可以通过引用来获取您的论点:

        BirdHouse(Bird& aa, Bird& bb, Bird& cc) : b(aa), bp(&bb), br(cc) {}
        

        【讨论】:

          【解决方案4】:
          BirdHouse(Bird aa, Bird bb, Bird cc) : b(aa), bp(&bb), br(cc) {}
          //                 ^^^^^^^, this is a temporary object (i.e., it won't exist
          //                          after the constructor completes
          

          上面你取一个地址给一个临时参数。如果您尝试在构造函数的主体中使用bp。但是,一旦构造函数完成,临时对象就消失了,但bp 仍然指向该内存地址。最后,一旦print 函数被执行,它就会取消引用一个不再指向有效对象且行为未定义的指针。

          根据您的用例,您可以将构造函数更改为:

          A)

          BirdHouse(Bird aa, Bird& bb, Bird& cc) : b(aa), bp(&bb), br(cc) {}
          

          B)

          BirdHouse(Bird aa, Bird* bb, Bird& cc) : b(aa), bp(bb), br(cc) {}
          

          注意:调用者需要清楚bbbr 的生命周期至少需要与BirdHouse 实例的生命周期一样长。 p>

          【讨论】:

          • 请注意,我们不知道是否存在所有权转让——在鸟舍的情况下可能没有;)
          • @Quentin 是的,我同意所有权在这种情况下没有意义,但我认为一般来说这是有用的信息,但也许它只会混淆答案。
          猜你喜欢
          • 1970-01-01
          • 2013-09-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-10-19
          • 1970-01-01
          相关资源
          最近更新 更多