How to pass in constructor arguments with new

Note 1: Using the standard library (namely std::vector in this case) to handle things is prefereable!

Note 2: Personally, I wouldn't go down the array of pointers route because you destroy your memory locality.

You can use std::allocator :

// Create allocator object
std::allocator<Point> alloc;
// allocate storage for k Points
Point * p = alloc.allocate(k);
// Construct k Points in p
for (std::size_t i{0}; i<k; ++i)
{
  alloc.construct(p+i, 5);
}
// Do stuff using p
// ...
// Destroy k objects in p
for (std::size_t i{0}; i<k; ++i)
{
  alloc.destroy(p+i);
}
// Dealloacte memory
alloc.deallocate(p, k);

or you can handle it manually

// allocate
Point * p = static_cast<Point*>(::operator new[](k*sizeof(Point)));
// placement new construction
for (std::size_t i{0}; i<k; ++i)
{
  new((void *)(p+i)) Point{5};
}
// stuff
// destruction
for (std::size_t i{0}; i<k; ++i)
{
  (p+i)->~Point();
}
// deallocation
::operator delete[](static_cast<void*>(p));

where I'd wrap the memory handling into functions (if not a class) at least:

#include <new>
#include <utility>
#include <cstddef>

template<class T, class ... Args>
T * new_n(std::size_t const n, Args&&  ... args)
{
  T * p{ (T*)::operator new[](n*sizeof(T)) };
  for (std::size_t i{ 0 }; i < n; ++i) 
  {
    new((void*)(p + i)) T(std::forward<Args>(args)...);
  }
  return p;
}

template<class T>
void remove_n(T * const p, std::size_t const n)
{
  for (std::size_t i{ 0 }; i < n; ++i) (p + i)->~T();
  ::operator delete[]((void*)p);
}

and use them

auto p = new_n<Point>(k, 5);
// stuff using k Points in p constructed by passing 5 to constructors
remove_n(p, k);

If you cannot use std::vector, then an option is to dynamically allocate an array of pointers, then dynamically allocate n objects and assign the resulting memory to the pointers in the array. For example:

constexpr auto ARRAYSIZE = 5;

auto x = new PointPtr[ARRAYSIZE];  // should check for memory alloc errors
for (int i = 0; i < ARRAYSIZE; ++i)
{
    x[i] = new Point(5); // pass any arguments you want, remember to check if allocation was successful
}

Note that such practices frowned upon because you should really never use new unless you have a very good reason to do so (and IMO it's stupid that you're not allowed to do things the proper way and taught good practices from the start); instead use std::vector and smart pointers, they should be able to satisfy all your dynamic memory needs.


I would suggest using a std::vector:

std::vector<Point> v(k, Point{5});

But you can also do it as:

Point* centroids = new Point[5]{{1}, {2}, {3}, {4}, {5}};

Live Demo

Tags:

C++