0

I want to create a simple template arraylist class but when i do something like

T* typeArray = new T[10];

this creates 10 instances of the object, calling the constructor 10 times. How can i create an empty array were i can later place objects?

7
  • How would you "later place objects"? You'd have to use placement new, not simple assignment... Commented Apr 15, 2013 at 19:15
  • typeArray[index] = ...; this wouldnt work? Commented Apr 15, 2013 at 19:17
  • 1
    Nope. You should use a vector. Commented Apr 15, 2013 at 19:20
  • 1
    @JavaNewb: You would probably want std::shared_ptr or std::unique_ptr instances instead so that deallocating the thing causes delete to be called on the underlying bits automatically. Of course, it is likely that doing all those allocations would be far more expensive than just calling constructors. Commented Apr 15, 2013 at 19:20
  • 1
    Look into how the standard allocators do their magic. They allocate chunks of char and then use placement new to construct objects in the chunks. When doing this you need to be careful about alignment. Commented Apr 15, 2013 at 19:23

2 Answers 2

5

It's not the preferred way of doing things in C++, but

T* my_array = (T*)malloc(10 * sizeof(T));

A solution more in line with standard C++ practice is

std::vector<T> my_vector;
my_vector.reserve(10);

Note, (as alluded to in comments) the solution with reserve differs in that without further action my_vector[5] is not valid whereas my_array[5] is. You will subsequently need something like my_vector.resize(10) in order to index it, which will construct all 10 items. You can construct them front-to-back by doing push_back(T const&) or emplace_back(Args...&& args). Only after constructed this way is [] indexing legal. As a warning, [] indexing may work even when illegal, but it is undefined behavior.

Sign up to request clarification or add additional context in comments.

6 Comments

std::array will cause constructor calls. +1 for the vector answer.
@BillyONeal Realized that, deleted.
... and what exactly do you recommend the OP do with that vector? Because there is a right and wrong answer just hanging there....
@Yakk I guess, hang on to it until he wants to put objects into it? I've never been in a situation where I wanted to allocate first but delay construction to some later point, but maybe that's the situation OP is in somehow. If "How can i create an empty array were i can later place objects?" is the question I don't see how either part of my answer is wrong.
The OP may be tempted to just do my_vector[0], which is undefined behavior that will sometimes work, misleading the OP into thinking that they did nothing wrong. :) I just think you should mention what to do with your my_vector once you reserve!
|
3
template<typename T>
struct RawMem {
  alignas(T) unsigned char data[sizeof(T)];
  T& get_unsafe() { return *reinterpret_cast<T*>(&data[0]); }
  T const& get_unsafe() const { return *reinterpret_cast<T const*>(&data[0]); }
  template<typename... Args>
  void Construct( Args&&... args ) {
    new (&data[0]) T( std::forward<Args>(args)... );
  }
  void Destroy() {
    get_unsafe().~T();
  }
};

RawMem<std::string>* buff = new RawMem<std::string>[10];
for (int i = 0; i < 10; ++i) {
  buff[i].Construct( "bob is your uncle" );
}
for (int i = 0; i < 10; ++i) {
  std::cout << buff[i].get_unsafe() << "\n";
}
for (int i = 0; i < 10; ++i) {
  buff[i].Destroy();
}
delete buff;

note that you are completely in charge of handling when the destructor is called, and when it isn't, with the above pattern.

I included helper Construct and Destroy functions so you don't have to mess around with placement new and the like yourself. Similarly, get_unsafe() will let you get ahold of the T& instance when you want it.

The above uses C++11 alignas, because there is no way in C++03 to solve the problem.

2 Comments

@BillyONeal Horror at the lack of unique_ptr, but not at the array of manually constructed objects with no state that describes which is constructed and which not?
Yes. At least your example RawMem might accomplish something useful in some limited cases. There's no reason at all for having a manual delete in new code (unless writing an RAII class itself). Of course, some form of state should go into RawMem in order to ensure the contained T gets destroyed...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.