Carousel
Carousel

Reputation: 738

Looking for a smart pointer which will copy the underlying resource when copying the smart pointer itself

Motivation

Imagining that there is a very large class A, and I wanna store it in a vector and I also want the vector to be copyable. Thus, smart pointer like std::shared_ptr and std::unique_ptr would not be nice choices. I know I could store objects of A in std::vector<A> directly. But as I said, A is a very large class. And since elements of std::vector<A> reside continuously in memory, there is a big chance that std::vector<A> needs to reallocate memory if I update it frequently. So, I need a "smart pointer" (let's say copyable_ptr) which will copy the underlying resource when copying the smart pointer itself. Then I could use std::vector<copyable_ptr<A>> to manage objects of A.

Here is a snippet template class of copyable_ptr:

template <typename T> class copyable_ptr {
  public:
    explicit copyable_ptr(T *p) : p(p) {}
    copyable_ptr(copyable_ptr const &rhs) : p(new T(*rhs.p)) {}
    copyable_ptr(copyable_ptr &&rhs) : p(rhs.p) { rhs.p = nullptr; }
    ~copyable_ptr() { delete p; }
    copyable_ptr &operator=(copyable_ptr rhs) {
        swap(rhs);
        return *this;
    }
    void swap(copyable_ptr &rhs) {
        using std::swap;
        swap(p, rhs.p);
    }
    T &operator*() const { return *p; }
    T *operator->() const { return &this->operator*(); }

    /* other members */

  private:
    T *p;
};

template <typename T>
inline void swap(copyable_ptr<T> &lhs, copyable_ptr<T> &rhs) {
    lhs.swap(rhs);
}

Question

Is there similar class that I can use directly or should I write my own or Is there any other appropriate solutions to store big class in container?

Edit

I think I should explain myself more clearly. A is a very large class, and I wanna use std::vector to manage objects of A. Basically, there are four options to do the job:

std::vector<std::shared_ptr<A>> a1;    // #1
std::vector<std::unique_ptr<A>> a2;    // #2
std::vector<A *> a3;    // #3
std::vector<A> a4;    // #4

I do not want to share objects of A, which makes #1 inappropriate. The vector will not be copyable in #2, and I have to take care of memory management manually in #3. So, only #4 lefts.

However, what I don't like about #4 is when size of a4 reaches its capacity, reallocating happens. Double size of a4 will be reserved (as I said, A is a very large class, isn't it inappropriate to reserve so much continuous memory in heap just for potential usage?). And What's worse is we perhaps need to move every single element of a4 to the newly allocated memory from old memory location. Another backward of #4 that I forgot to mention when I asked the question is it's not polymorphic support.

So, if I use std::vector<copyable_ptr<A>> to manage objects of A, all the problems I mentioned above seems be handled properly. All you need is a well designed copyable_ptr class, and that's what I'm looking for.

Upvotes: 3

Views: 616

Answers (3)

one_two_three
one_two_three

Reputation: 559

Not exactly the answer to question, but if this:

However, what I don't like about #4 is when size of a4 reaches its capacity, reallocating happens.

is your main concern and if your are Ok with storing your classes in non-contiguous memory with slightly slower direct access by index, you can use std::deque instead of std::vector.

Upvotes: 0

evan
evan

Reputation: 1693

As far as I know, there is no such smart pointer in the standard library. Your copyable_ptr seems to do the job. I've used such things in the past, though for polymorphic classes instead of just really big classes.

Upvotes: 1

Sam Varshavchik
Sam Varshavchik

Reputation: 118435

Yes, there is such a thing: it's called the class itself.

The whole purpose of a smart pointer is to provide a reference-counted handle for an object, that can be passed around, without copying the underlying object, and automatically destroy the object when the reference count goes down to 0, and the last smart pointer referencing the object goes out of scope, and it gets destroyed (with certain variations of reference-counting semantics between shared_ptr, unique_ptr, et al).

If you want to have some kind of a pointer to an object that copies it, when copying the pointer, you don't need a pointer for that. Just use the object directly, by value. Every time you copy it, you're guaranteed to copy the object, by definition.

Having some kind of pointer, around, adds absolutely nothing of value. You want to use the object directly, copy it when needed, etc... Just use the object.

Upvotes: 3

Related Questions