3

I have a class containing a c-style array managed with unique_ptr. I want to provide a constructor:

class A {
  unique_ptr<T[]> p;
public:
  A(int d, X x) : p(new T[d]) {
    //Transfer from x to p without copying
  }
}

so that I can build my object with something like:

int main(..) {
  A a{n,{expr1,expr2,..}};
}

where {expr1,expr2,..} contains the values (evaluated at runtime) for the inizialization. Since this list is temporary, it seems to me a waste of resources to build it, copying its values into the actual object and discard it.

I believe that with move semantincs, rvalues and all the nice features of C++11 there should be a solution for this simple task, but I could not find it (I'm quite new in C++).

I would like to stick with c-style arrays and don't move to std::vectors. Is there a solution?

M.M
  • 130,300
  • 18
  • 171
  • 314
Teloze
  • 219
  • 1
  • 7
  • What do you mean by "without copying"? You want the heap allocation to be initialized with the data members? – Justin May 25 '17 at 20:57
  • 1
    Don't use `unique_ptr` for arrays. Use `std::array`, `std::vector` or `std::string` as pointed out by @Ðаn. –  May 25 '17 at 21:10

2 Answers2

2

There are tow points I'd like to make here.

  1. AFAICS, std::unique_ptr<T[]> offers you very little benefit over the standard C++ solution of using a std::vector<T>, namely a reduced memory footprint (64 instead of 128 bytes for the container itself on a 64bit machine and potentially also of the amount of heap used), but see the discussion here. Any newby to C++ should stick to std::vector.

  2. Move semantics are only beneficial for objects that manage memory on the heap ('free store'). So only if your expr1, expr2 etc are object which themselves keep track of allocated memory, does moving have any meaning. This does not appear the case here, so just copy.

Walter
  • 40,885
  • 16
  • 97
  • 176
  • Re. 2, `T` might be `std::string` or some more compliated class – M.M May 25 '17 at 23:30
  • @Walter I don't fully understand your second comment. Maybe I'm getting everything wrong but I can imagine someone to build a temporary object on the stack and than "move" this object as data member of a class. – Teloze May 26 '17 at 09:59
  • 1
    @user8066678 You seem to not have grasped the idea of moving yet. If you create a temporary object on the stack, you cannot move it. Moving means: copy the pointer to an object on the heap (rather than copying the object itself), but then ensure that the pointer variable copied from is reset to null. It is similar to what otherwise is referred to a 'shallow copy' (e.g. in python). – Walter May 26 '17 at 13:19
2

Yes, you can use perfect forwarding:

#include <memory>
#include <string>

struct S
{
    S(int) {}
    S(S const&) = delete;
    S(S&&) = default;
};

template<typename T>
struct A
{
    std::unique_ptr<T[]> p;

    template<typename... Args>
    A(int d, Args&&... args)
        : p(new T[sizeof...(args)]{std::forward<Args>(args)...})
    {
    }
};

int main()
{
    A<int> a(0, 1, 2, 3, 4);

    A<std::string> b(0, "hello", "world!", "\n");

    S s(0);
    A<S> c(0, std::move(s), 2, 3);
}
M.M
  • 130,300
  • 18
  • 171
  • 314