Hanley
Hanley

Reputation: 123

I need some C++ structure advice

I have one instance of Class A. It has two members, Object A and Object B. I need to create ONE instance of Object A (which is quite a large object), and TWO instances of object B, and then give both instances of object B access to that object A. They don't ever need to change object A, they just need to access its info.

Right now, I got it all to work by creating Object A as a pointer, passing it into both instances of Object B, who have their own pointer that then points to the same place in memory as Object A's pointer. This works fine, but I think that's a pretty big No-No right? Because once Class A deletes the original pointer I'll have some dangling pointers, right? Is there a better way to do this?

(FYI - Object A takes a couple seconds to load at a time in the program where I need a fast load time, that's why I have to create only one instance and pass it to both of Object Bs instead of letting Object B create their own instances of Object A. )

Upvotes: 0

Views: 117

Answers (2)

Steve Jessop
Steve Jessop

Reputation: 279255

Provided that the "B-things" don't outlive the "big object that they both have a pointer to", then you won't have a dangling pointer when the "big object" is deleted.

If "one instance of Class A" has both of those objects as data members, then they'll all be destroyed at the same time (well, in reverse order that they're declared in the class, but close to the same time), so it should be reasonably easy to ensure that the dangling pointer is never used.

On the other hand, if you pass pointers to the "big object" around willy-nilly, store them in all sorts of different places with unknown lifetimes, and then delete the "big object" -- sure, that's a no-no. The problem is "willy-nilly" - you need to keep control and make sure that the big object outlives the objects that point to it.

For example, the following is perfectly safe:

struct Big {
    // big stuff
};

struct Little {
    Little(const Big *a) : bigthing(a) {}
    // stuff that uses bigthing
  private:
    const Big *bigthing;
};

struct Foo {
    Big onlybigthing;
    Little firstlittlething;
    Little secondlittlething;
    Foo() : 
        onlybigthing(), 
        firstlittlething(&onlybigthing), 
        secondlittlething(&onlybigthing) 
    {}
};

provided of course that the instances of Little don't hand out their pointer to Big, to anyone who comes asking for it and then stores it beyond the lifetime of the Foo object. Likewise Foo has to avoid handing out copies of the instances of Little to someone who might store those (and the pointer with them).

But you say that your class A has two members, whereas here I have three (one Big and two Little) because you also say that you create three instances of those two objects. I don't understand what that means.

Here's another example of something that's safe:

int main() {
    Big big;
    Little little1(&big);
    Little little2(&big);
}

Here's a third example of something that's safe:

struct Little {
    Little(const std::shared_ptr<Big> &a) : bigthing(a) {}
    // stuff that uses bigthing
  private:
    std::shared_ptr<Big> bigthing;
};

int main() {
    std::shared_ptr<Big> big(new Big());
    Little little1(big);
    Little little2(big);
    big.reset(); // release our shared ownership
    // safely do stuff using little1 and little2

    return 0;
    // on exit, little2 is destroyed first, then when little1 is destroyed
    // it releases the last shared ownership of the instance of `Big`,
    // which is destroyed.
}

Upvotes: 1

Some programmer dude
Some programmer dude

Reputation: 409186

If I follow you correctly, you want something like this:

// Class for "Object A" in your question
class Foo
{
    // ...
};

// Class for "Object B" in your question
class Bar
{
    Foo &foo_;

public:
    Bar(Foo &foo)
        : foo_(foo)
        {}
};

class A
{
    Foo foo_;
    Bar bar1_;
    Bar bar2_;

public:
    A()
        : bar1_(foo_),
          bar2_(foo_)
        {}
};

Using no pointers, no allocations, so no dangling pointers/references or memory leaks. When A gets destroyed so does bar1_ and bar2_ too along with foo_, so the two instances of Bar will not be left with any dangling references either.

Upvotes: 2

Related Questions