简体   繁体   中英

How to correctly use smart pointers in OOP

I am wondering what is the correct way to use std::unique_ptr in an Object-Oriented Programming. Let's say I have a class that contains an member object that can be passed by pointer

class B
{/*Some code here*/};

class A
{
public:
    A();
    B* getMember();
private:
    std::unique_ptr<B> member
};

First: Should the member be a std::unique_ptr or a std::shared_ptr to avoid memory leaks?

Second, what would be the implementation of my getter if in cases where I want to

  1. Allow modification of the member?
  2. Not allow modification of the member?

I initially did:

B* A::getMember()
{
    return member.get();
}

But I am considering to have the member be a std::shared_ptr and adapt the getter:

class A
{
public:
    A();
    std::shared_ptr getMember();
private:
    std::shared_ptr<B> member
};

std::shared_ptr A::getMember()
{
    return member;
}

What is the standard and most-widely accepted implementation?

shared_ptr implies a complex ownership rule where the object in question is owned by multiple co-equal parties, and its lifetime cannot be determined easily. Deciding to go with shared_ptr because it is simpler or easier is like using a bazooka to kill a fruit fly bothering you because it is more powerful than a fly swatter.

In C++ there is no simple way to avoid thinking about ownership.

unique_ptr provides a simple owned-by relationship to manage lifetimes. Value types (or types with value semantics) provide even simpler lifetime management. Nobody gets confused by the lifetime of int x=7; past a novice.

C++ can support runtime polymorphic value types; see std::function . When in doubt use values.

class A {
public:
  A();
  B b;
};

far easier to think about.

Now, if you are doing something like a UI framework, then your UI elements are going to be owned by your framework. You'll probably want a naming system, configuration files in an ASL, and a way to connect your UI to actions and modify your UI with code.

Next to none of this will involve a class with a member subobject returning pointers to it via accessors.

Maybe your UI is immutable copy on write shared ptr data attached to names you can get/setfrom the framework. Here the immutable data is truely shared; it acts like an integer.

Regardless, you have to think about what it means for a B to exist seperate from an A whenever you share a B pointer, be it dumb, unique, shared, immutable or copy on write. Either B becomes some interface to some part of A's state, in which case its lifetime is logically tied, or it lives independently, in which case you probably want value semantics.

And having made that decision, a shared ptr is probably the wrong lifetime rule. If it is an interface to part of A's state, it outliving A as implied by shared ownership is an error, and if it is a value you set/get, getting it and modifying the state implicitly acts as an interface to A's state! Sithout A even knowing!

A being deliver ed state change notifications from a B? Bring able to get the B that provides state change notifications? Sensible; here, B could be UI theming colour, and A a control. But here A probably has a shared ptr to a const theme color set plus a subscription token to theme change messages. (here the colour set is legitimately shared)

In short, defaulting to shared ptr is bad. Use unique ptr when you cannot use values. Ownership follows lifetime, which follows from semantics. Default to values, C++ is one of the few OO languages that has really solid value support.

If you're handing out pointers to a unique_ptr then you're not really treating it as "unique".

What you really need is a shared_ptr . Your second approach is the correct way. These are intended to be copied as necessary and retain reference counts. This means so long as you hold a copy of the shared_ptr object, you're able to access it.

In the former case you have absolutely no clue if your pointer is still valid after the instant you receive it. You must manually track that, which is sort of defeating the point of using smart pointers.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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