简体   繁体   English

指向构造函数C ++中不同类的指针初始化

[英]Pointer initialization to different class in constructor c++

I have problem with initializing pointer to Bird in BirdHouse's constructor initialization list. 我在BirdHouse的构造函数初始化列表中初始化指向Bird的指针时遇到问题。 It seems that it doesn't point to the object that I want to point to. 似乎它没有指向我要指向的对象。

Here is the Bird class: 这是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;
};

And here is the BirdHouse class: 这是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;
    }
};

When I want to call BirdHouse::print() in main() the program crashes: 当我想在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;
}

How should I initialize BirdHouse object so it points to appropriate Bird object? 我应该如何初始化BirdHouse对象,使其指向适当的Bird对象?

The crash is because of undefined behavior , because you save a pointer to an argument that is passed by value, and that object will be destructed once the function returns. 崩溃是由于未定义的行为所致 ,因为您保存了指向由值传递的参数的指针,并且一旦函数返回,该对象将被破坏。

There are two possible solutions as I can see it: Either pass the variable as a pointer to begin with, or pass it by reference. 我看到有两种可能的解决方案:要么将变量作为指针开始,要么通过引用传递。 However, be careful because if the lifetime of the BirdHouse object is longer than the lifetime of the object you pass in (as a pointer or a reference) you will once again have undefined behavior. 但是,请小心,因为如果BirdHouse对象的生存期长于您传入的对象(作为指针或引用)的生存期,则将再次具有未定义的行为。

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

aa , bb and cc are parameters passed by values, which are local to your constructor. aabbcc是由值传递的参数,它们对于构造函数是本地的。 However, you store a pointer to bb and a reference to cc , which both become dangling when the constructor ends. 但是,您存储了指向bb的指针和对cc的引用,当构造函数结束时,它们都变得悬而未决。

When you try to access one of the dangling members in print() , you trigger Undefined Behaviour, in your case a crash. 当您尝试访问print()一个悬空成员时,您会触发未定义行为,如果发生崩溃。 Don't do that. 不要那样做

Turning up your compiler warnings will probably notify you about this problem. 出现编译器警告可能会通知您有关此问题的信息。

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

Here you take argument by value, thus creating a copy. 在这里,您可以按值接受参数,从而创建一个副本。 You then go on to store a pointer and reference to these copies which will be destructed at the end of the constructor. 然后,您继续存储指针和对这些副本的引用,这些副本将在构造函数的结尾处被销毁。 Now whenever you attempt to access these, you invoke undefined behaviour. 现在,无论何时尝试访问这些内容,都将调用未定义的行为。

To fix this, you could take your arguments in by reference instead: 要解决此问题,您可以通过引用代替您的参数:

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) {}
//                 ^^^^^^^, this is a temporary object (i.e., it won't exist
//                          after the constructor completes

Above you take an address to a temporary parameter. 在上方,您将地址设为一个临时参数。 If you tried to use bp in the body of the constructor. 如果您尝试在构造函数的主体中使用bp However, once the constructor completes the temporary object is gone but bp still points to that memory address. 但是,一旦构造函数完成,临时对象就消失了,但是bp仍然指向该内存地址。 Finally, once the print function is executed it dereferences a pointer which no longer points to a valid object and the behavior is undefined. 最后,一旦执行了print功能,它将取消引用不再指向有效对象的指针,并且该行为未定义。

Depending on your use case you could change your constructor to be: 根据您的用例,您可以将构造函数更改为:

A) 一种)

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

B) B)

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

Note: It needs to be clear to the caller that the lifetimes of bb and br need to last at least as long as the lifetime of the BirdHouse instance. 注意:调用者必须清楚bbbr的生存期至少要与BirdHouse实例的生存期一样长。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM