Initialize an array of classes?

B

Bob Altman

Hi all,

I have a class that contains a member variable that is an array of class
instances:

class MyClass {
private:
SomeClass m_someClass;
SomeClass m_arrayOfClasses[2];
};

Now, the SomeClass class doesn't have a default (paramterless) constructor,
so I need to call its constructor in my initialization list of the MyClass
constructor, kind of like this:

// Constructor
MyClass::MyClass(void) :
// This compiles ok
m_someClass( constructor_arguments ),

// This doesn't compile
m_arrayOfClasses[0]( constructor_arguments ),
m_arrayOfClasses[1]( constructor_arguments )
{}

How do I initialize the array of class instances?

TIA - Bob
 
B

Bob Altman

Here is a complete C++ console app example that demonstrates what I'm trying
to do. The challenge is to change InnerValue to an array and figure out how
to call the constructor for each element of the array.

TIA - Bob

#include "stdafx.h"
#include <iostream>
using namespace std;

class CInner {
public:
// Constructor
CInner(int x) : Value(x) {}

// Member variable
int Value;
};

class COuter {
public:
CInner InnerValue;

// Constructor
COuter() :
InnerValue(2)
{}
};

int _tmain(int argc, _TCHAR* argv[])
{
COuter x;
cout << x.InnerValue.Value << endl;
return 0;
}
 
B

Bob Altman

Well, I found a way to get kind of what I'm after. Instead of trying to
have an array of class instances, I can create an array of pointers to class
instances. That way I can use the "new" operator in the body of the
constructor to initialize the array. Of course, this means that I need to
go through my code and change all of the relevant "." operators to "->"
operators, but that's easily enough done in this case.

But I'm still curious as to whether or not it's possible to initialize an
array of classes if the class doesn't have a default constructor.
 
D

David Wilkinson

Bob said:
Hi all,

I have a class that contains a member variable that is an array of class
instances:

class MyClass {
private:
SomeClass m_someClass;
SomeClass m_arrayOfClasses[2];
};

Now, the SomeClass class doesn't have a default (paramterless) constructor,
so I need to call its constructor in my initialization list of the MyClass
constructor, kind of like this:

// Constructor
MyClass::MyClass(void) :
// This compiles ok
m_someClass( constructor_arguments ),

// This doesn't compile
m_arrayOfClasses[0]( constructor_arguments ),
m_arrayOfClasses[1]( constructor_arguments )
{}

How do I initialize the array of class instances?

Bob:

If SomeClass is copyable you can do

MyClass::MyClass():
m_someClass( constructor_arguments )
{
m_arrayOfClasses[0] = SomeClass( constructor_arguments0 );
m_arrayOfClasses[1] = SomeClass( constructor_arguments1 );
}
 
B

Bo Persson

Bob said:
Well, I found a way to get kind of what I'm after. Instead of
trying to have an array of class instances, I can create an array
of pointers to class instances. That way I can use the "new"
operator in the body of the constructor to initialize the array. Of
course, this means that I need to go through my code and change
all of the relevant "." operators to "->" operators, but that's
easily enough done in this case.
But I'm still curious as to whether or not it's possible to
initialize an array of classes if the class doesn't have a default
constructor.

No, there is no way of initializing member array in the current
language.

In the upcoming revision, C++09, there is a generalized "initializer
list" feature that will possibly help in cases like this.


Bo Persson
 
C

Charles Wang [MSFT]

Hi Bob,
Currently you cannot use member initialization list for a nonstatic array of a class if it does not have a default constructor. When you try to initialize the array, you will encounter the compiler
error C2536. You may refer to:
Compiler Error C2536
http://msdn.microsoft.com/en-us/library/9f53ks1w.aspx

If the class has a default constructor, you can explicitly initialize it like the following code:
class CInner {
public:
// Constructor
CInner(int x) : Value(x) {}
CInner(){}

// Member variable
int Value;
};

class COuter {
public:
CInner InnerValue;
CInner m_Inners[2];

// Constructor
COuter() :
InnerValue(2),m_Inners()
{}
};

The code can be compiled, however you may encounter the warning C4351 and I do not think that it is useful to use such initialization for an array.
You can refer to this article for further inforamtion:
Compiler Warning (level 1) C4351
http://msdn.microsoft.com/en-us/library/1ywe7hcy.aspx

Best regards,
Charles Wang
Microsoft Online Community Support
===========================================================
Delighting our customers is our #1 priority. We welcome your
comments and suggestions about how we can improve the
support we provide to you. Please feel free to let my manager
know what you think of the level of service provided. You can
send feedback directly to my manager at: (e-mail address removed).
===========================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notifications.

Note: The MSDN Managed Newsgroup support offering is for
non-urgent issues where an initial response from the community
or a Microsoft Support Engineer within 1 business day is acceptable.
Please note that each follow up response may take approximately
2 business days as the support professional working with you may
need further investigation to reach the most efficient resolution.
The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by
contacting Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
============================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
=========================================================
 
B

Ben Voigt [C++ MVP]

David said:
Bob said:
Hi all,

I have a class that contains a member variable that is an array of
class instances:

class MyClass {
private:
SomeClass m_someClass;
SomeClass m_arrayOfClasses[2];
};

Now, the SomeClass class doesn't have a default (paramterless)
constructor, so I need to call its constructor in my initialization
list of the MyClass constructor, kind of like this:

// Constructor
MyClass::MyClass(void) :
// This compiles ok
m_someClass( constructor_arguments ),

// This doesn't compile
m_arrayOfClasses[0]( constructor_arguments ),
m_arrayOfClasses[1]( constructor_arguments )
{}

How do I initialize the array of class instances?

Bob:

If SomeClass is copyable you can do

MyClass::MyClass():
m_someClass( constructor_arguments )
{
m_arrayOfClasses[0] = SomeClass( constructor_arguments0 );
m_arrayOfClasses[1] = SomeClass( constructor_arguments1 );
}

Don't think so... all members have to be fully constructed before the body
of the user-defined constructor begins to execute. With no parameter-less
constructor, and no way to pass parameters to the array element
constructors, it's not possible.

OTOH, you should be able to make a fixed-length std::vector alike that does
this, using an embedded char array, sizeof, and placement new. Be careful
about destroying the right set of already-fully-constructed elements if any
of the element constructors throw, be careful to destroy the elements in the
array's destructor, and block copy construction and assignment operators,
and you should be golden. This will, of course, be a lot more general in
C++0x with variadic templates and closures, but C++03 is perfectly capable
of making a type-specific initializable array class.
 
D

David Wilkinson

Ben said:
David said:
Bob said:
Hi all,

I have a class that contains a member variable that is an array of
class instances:

class MyClass {
private:
SomeClass m_someClass;
SomeClass m_arrayOfClasses[2];
};

Now, the SomeClass class doesn't have a default (paramterless)
constructor, so I need to call its constructor in my initialization
list of the MyClass constructor, kind of like this:

// Constructor
MyClass::MyClass(void) :
// This compiles ok
m_someClass( constructor_arguments ),

// This doesn't compile
m_arrayOfClasses[0]( constructor_arguments ),
m_arrayOfClasses[1]( constructor_arguments )
{}

How do I initialize the array of class instances?
Bob:

If SomeClass is copyable you can do

MyClass::MyClass():
m_someClass( constructor_arguments )
{
m_arrayOfClasses[0] = SomeClass( constructor_arguments0 );
m_arrayOfClasses[1] = SomeClass( constructor_arguments1 );
}

Don't think so... all members have to be fully constructed before the body
of the user-defined constructor begins to execute. With no parameter-less
constructor, and no way to pass parameters to the array element
constructors, it's not possible.

OTOH, you should be able to make a fixed-length std::vector alike that does
this, using an embedded char array, sizeof, and placement new. Be careful
about destroying the right set of already-fully-constructed elements if any
of the element constructors throw, be careful to destroy the elements in the
array's destructor, and block copy construction and assignment operators,
and you should be golden. This will, of course, be a lot more general in
C++0x with variadic templates and closures, but C++03 is perfectly capable
of making a type-specific initializable array class.

Ben:

Mmmm, I guess you're right. Oh well.

Of course, this could be fixed by creating a default constructor for SomeClass...
 
P

Paul Pavlicko

Bob - I am trying to do something very similar by having an array of a class
inside the other class but have the array created dynamically through the
main class constructor.

can I see your code on how you did this with the pointers?
 
B

Ben Voigt [C++ MVP]

Paul said:
Bob - I am trying to do something very similar by having an array of
a class inside the other class but have the array created dynamically
through the main class constructor.

can I see your code on how you did this with the pointers?
 
B

Bob Altman

Paul, I just hacked up my original post. No guarantees that I didn't mangle
something...

#include "stdafx.h"
#include <iostream>
using namespace std;

class CInner {
public:
// Constructor
CInner(int x) : Value(x) {}

// Member variable
int Value;
};

class COuter {
public:
CInner InnerValue[5]; // Won't compile
CInner* InnerValue[5] // Array of pointers

// Constructor
COuter() :
// InnerValue(2) // Remove initializer
{
// Initialize the array in the body of the constructor
for (int i = 0; i < 5; i++) {
InnerValue = new CInner(i);
}
}
};

int _tmain(int argc, _TCHAR* argv[])
{
COuter x;
cout << x.InnerValue.Value << endl;
return 0;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top