在构造函数 c++ 中指向不同 class 的指针初始化

Pointer initialization to different class in constructor c++

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

这是鸟 class:

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:

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 对象?

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

aabbcc 是按值传递的参数,这些参数对于您的构造函数而言是本地的。但是,您存储了一个指向 bb 的指针和一个对 cc 的引用,它们在构造函数结束时都变为悬空状态。

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

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

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) {}

崩溃是因为未定义的行为,因为你保存了一个指向按值传递的参数的指针,一旦函数returns.

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

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 个实例。