2

I'm trying to dynamically allocate an array of objects. Each of my objects have a parameter in their constructor that must be initialized. I would prefer to initialize them at construction time, because I think it would save time. How do I initialize an array of dynmaically allocated objects at allocation time, with a constructor that requires a parameter?

class Thingy{
private:
    int* a;
public:
    Thingy(int size);
};

class ThingyLayer{
private:
    Thingy* m_things;
public:
    ThingyLayer(int n){
        m_things = new Thingy[n]; //!< How do I pass a param here to the ctor of Thingy
    }
};

I would prefer not to use std::vector in this case, because some day I might want to run this on an embedded system that doesn't support STL, like the Atmel AVR chips. So I am looking for how to do this with pointers.

I've already tried, m_things = new Thingy[n](val), but that doesn't work as it raises a compiler warning. I also viewed Dynamically allocating an array of objects, but that did not answer my question.

Community
  • 1
  • 1
HSchmale
  • 1,838
  • 2
  • 21
  • 48
  • The same parmeter for all elements ? – Christophe Jun 09 '15 at 18:48
  • @Christophe The same parameter for all. – HSchmale Jun 09 '15 at 18:48
  • Just because a feature exists in the language, doesn't mean it should ever be used. The array form of `new` is one of those things. – Benjamin Lindley Jun 09 '15 at 18:50
  • Apparently, there is `std::vector` for AVR, and it is small enough for 16k chips: http://andybrown.me.uk/wk/2011/01/15/the-standard-template-library-stl-for-avr-with-c-streams/ (unchecked, I never used that). – Baum mit Augen Jun 09 '15 at 18:57
  • You can overload operator new[] to allow passing the parameter, or use a default value for the parameter. See http://www.drdobbs.com/cpp/calling-constructors-with-placement-new/232901023 – vsoftco Jun 09 '15 at 19:00
  • Not having std::vector pre-provided is no excuse. You should simply create it if not available. It does not change the fact that not using std::vector is stupid. – Puppy Jun 09 '15 at 19:17
  • What compiler warning is `new Thingy[n](val)` generate? That is valid syntax intended exactly for this purpose --not that you should need to do this, as you should use a vector class (if the target environment does not have STL, you can probably use available, or at the worst case implement one yourself when need comes. Trying to reinvent the wheel is going to make everything much more painful than needed... do simple things first, then if needed work on small parts if you really need to change things for some specific reason. – David Rodríguez - dribeas Jun 09 '15 at 19:22
  • @DavidRodríguez-dribeas The warning was about the -fpermissive flag being required. – HSchmale Jun 09 '15 at 19:27
  • @HSchmale: that is not the warning, but how to silence it. This is akin to asking how the car noise sounded and the answer being that turning it off the engine. – David Rodríguez - dribeas Jun 09 '15 at 19:29
  • @DavidRodríguez-dribeas I'm getting `array 'new' cannot have initialization arguments` in both g++ and clang++. How does it work? – vsoftco Jun 09 '15 at 19:34
  • @vsoftco: interesting... I learned something today. – David Rodríguez - dribeas Jun 09 '15 at 23:39
  • @DavidRodríguez-dribeas It (kind) of works with C++ list init., `new int[1024]{42};`, however this makes only the first element `42` then zero initializes the rest. – vsoftco Jun 09 '15 at 23:55

2 Answers2

4

The C++ way to do this is std::vector (and I do not believe you that you really have a good reason to use a pointer instead Ok, you named a reason, and I cannot really judge if it is a good one because I have no knowledge about embedded systems):

class ThingyLayer{
private:
    std::vector<Thingy> m_things;
public:
    ThingyLayer(int n) : m_things(n,val){}
};

This also safes you the pain of manually newing and deleteing stuff, which is not a fun thing to do correctly.

std::vector also comes with a whole bunch of other neat features, check out the man page I linked if you are not familiar with it.

Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182
1

You might be able get by using:

ThingyLayer(int n){
    char* temp = new char[sizeof(Thingy)*n];
    for (int i = 0; i < n; ++i )
    {
        // Use placement new to construct Thingy objects.
        new (temp+i*sizeof(Thingy)) Thingy(10); // Assuming 10 here.
    }
    m_things = reinterpret_cast<Thingy*>(temp);
}

I am a bit hesitant since the alignment requirements of Thingy are char are different. I am not sure how that affects the behavior of the code.

If you follow this path, ThingyLayer's destructor has to be carefully crafted too.

class ThingyLayer
{
   private:
      int m_n;
      Thingy* m_things;
   public:
      ThingyLayer(int n) : m_n(n) {
         char* temp = new char[sizeof(Thingy)*n];
         for (int i = 0; i < n; ++i )
         {
            // Use placement new to construct Thingy objects.
            new (temp+i*sizeof(Thingy)) Thingy(10); // Assuming 10 here.
         }
         m_things = reinterpret_cast<Thingy*>(temp);
      }

      ~ThingyLayer()
      {
         for (int i = 0; i < m_n; ++i )
         {
            // Call the destructor of Thingy explicitly.
            m_things[i].~Thingy();
         }

         // Now deallocate the memory using a char*.
         char* temp = reinterpret_cast<char*>(m_things);
         delete [] temp;
      }

      // Make sure to implement copy constructor and copy assignment 
      // operator properly. If you use the default copy constructor and
      // copy assignment operator, the program will exhibit undefined
      // behavior.

      ThingyLayer(ThingyLayer const& copy) { ... }
      ThingyLayer& operator=(ThingyLayer const& rhs) { ... }

};

Further reading: What is The Rule of Three?

Community
  • 1
  • 1
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • If you follow this path you will have to also manually delete the objects and then `delete []` after casting to a `char *`... I would not quite recommend this. – David Rodríguez - dribeas Jun 09 '15 at 19:18
  • What would the clean up code be for this? Would it require multiple casts when cleaning up? – HSchmale Jun 09 '15 at 19:22
  • If you can't use vector, then the next best thing is to implement vector yourself, and this is (basically) what vector does. But don't forget the [rule of three/five](http://en.cppreference.com/w/cpp/language/rule_of_three). – Benjamin Lindley Jun 09 '15 at 19:48
  • I'm getting a compiler error on `m_things[i]::~Thingy();`, The compiler says that it expected `;` before `::`. What does that mean? – HSchmale Jun 09 '15 at 20:10
  • @HSchmale: It means this bloke invented syntax. He meant `m_things[i].~Thingy();` He also forgot the copy constructor and assignment operator, making this class very broken. – Lightness Races in Orbit Jun 09 '15 at 21:47
  • @HSchmale, sorry about the compiler errors. It's fixed now. – R Sahu Jun 09 '15 at 21:57