I'm having a brain cramp... how do I initialize an array of objects properly in C++?
non-array example:
struct Foo { Foo(int x) { /* ... */ } };
struct Bar {
Foo foo;
Bar() : foo(4) {}
};
array example:
struct Foo { Foo(int x) { /* ... */ } };
struct Baz {
Foo foo[3];
// ??? I know the following syntax is wrong, but what's correct?
Baz() : foo[0](4), foo[1](5), foo[2](6) {}
};
edit: Wild & crazy workaround ideas are appreciated, but they won't help me in my case. I'm working on an embedded processor where std::vector and other STL constructs are not available, and the obvious workaround is to make a default constructor and have an explicit init() method that can be called after construction-time, so that I don't have to use initializers at all. (This is one of those cases where I've gotten spoiled by Java's final keyword + flexibility with constructors.)
Edit: see Barry's answer for something more recent, there was no way when I answered but nowadays you are rarely limited to C++98.
There is no way. You need a default constructor for array members and it will be called, afterwards, you can do any initialization you want in the constructor.
Just to update this question for C++11, this is now both possible to do and very natural:
struct Foo { Foo(int x) { /* ... */ } };
struct Baz {
Foo foo[3];
Baz() : foo{{4}, {5}, {6}} { }
};
Those braces can also be elided for an even more concise:
struct Baz {
Foo foo[3];
Baz() : foo{4, 5, 6} { }
};
Which can easily be extended to multi-dimensional arrays too:
struct Baz {
Foo foo[3][2];
Baz() : foo{1, 2, 3, 4, 5, 6} { }
};
Right now, you can't use the initializer list for array members. You're stuck doing it the hard way.
class Baz {
Foo foo[3];
Baz() {
foo[0] = Foo(4);
foo[1] = Foo(5);
foo[2] = Foo(6);
}
};
In C++0x you can write:
class Baz {
Foo foo[3];
Baz() : foo({4, 5, 6}) {}
};
Unfortunately there is no way to initialize array members till C++0x.
You could use a std::vector and push_back the Foo instances in the constructor body.
You could give Foo a default constructor (might be private and making Baz a friend).
You could use an array object that is copyable (boost or std::tr1) and initialize from a static array:
#include <boost/array.hpp>
struct Baz {
boost::array<Foo, 3> foo;
static boost::array<Foo, 3> initFoo;
Baz() : foo(initFoo)
{
}
};
boost::array<Foo, 3> Baz::initFoo = { 4, 5, 6 };
You can use C++0x auto keyword together with template specialization on for example a function named boost::make_array() (similar to make_pair()). For the case of where N is either 1 or 2 arguments we can then write variant A as
namespace boost
{
/*! Construct Array from #p a. */
template <typename T>
boost::array<T,1> make_array(const T & a)
{
return boost::array<T,2> ({{ a }});
}
/*! Construct Array from #p a, #p b. */
template <typename T>
boost::array<T,2> make_array(const T & a, const T & b)
{
return boost::array<T,2> ({{ a, b }});
}
}
and variant B as
namespace boost {
/*! Construct Array from #p a. */
template <typename T>
boost::array<T,1> make_array(const T & a)
{
boost::array<T,1> x;
x[0] = a;
return x;
}
/*! Construct Array from #p a, #p b. */
template <typename T>
boost::array<T,2> make_array(const T & a, const T & b)
{
boost::array<T,2> x;
x[0] = a;
x[1] = b;
return x;
}
}
GCC-4.6 with -std=gnu++0x and -O3 generates the exact same binary code for
auto x = boost::make_array(1,2);
using both A and B as it does for
boost::array<int, 2> x = {{1,2}};
For user defined types (UDT), though, variant B results in an extra copy constructor, which usually slow things down, and should therefore be avoided.
Note that boost::make_array errors when calling it with explicit char array literals as in the following case
auto x = boost::make_array("a","b");
I believe this is a good thing as const char* literals can be deceptive in their use.
Variadic templates, available in GCC since 4.5, can further be used reduce all template specialization boiler-plate code for each N into a single template definition of boost::make_array() defined as
/*! Construct Array from #p a, #p b. */
template <typename T, typename ... R>
boost::array<T,1+sizeof...(R)> make_array(T a, const R & ... b)
{
return boost::array<T,1+sizeof...(R)>({{ a, b... }});
}
This works pretty much as we expect. The first argument determines boost::array template argument T and all other arguments gets converted into T. For some cases this may undesirable, but I'm not sure how if this is possible to specify using variadic templates.
Perhaps boost::make_array() should go into the Boost Libraries?
This seems to work, but I'm not convinced it's right:
#include <iostream>
struct Foo { int x; Foo(int x): x(x) { } };
struct Baz {
Foo foo[3];
static int bar[3];
// Hmm...
Baz() : foo(bar) {}
};
int Baz::bar[3] = {4, 5, 6};
int main() {
Baz z;
std::cout << z.foo[1].x << "\n";
}
Output:
$ make arrayinit -B CXXFLAGS=-pedantic && ./arrayinit
g++ -pedantic arrayinit.cpp -o arrayinit
5
Caveat emptor.
Edit: nope, Comeau rejects it.
Another edit: This is kind of cheating, it just pushes the member-by-member array initialization to a different place. So it still requires Foo to have a default constructor, but if you don't have std::vector then you can implement for yourself the absolute bare minimum you need:
#include <iostream>
struct Foo {
int x;
Foo(int x): x(x) { };
Foo(){}
};
// very stripped-down replacement for vector
struct Three {
Foo data[3];
Three(int d0, int d1, int d2) {
data[0] = d0;
data[1] = d1;
data[2] = d2;
}
Foo &operator[](int idx) { return data[idx]; }
const Foo &operator[](int idx) const { return data[idx]; }
};
struct Baz {
Three foo;
static Three bar;
// construct foo using the copy ctor of Three with bar as parameter.
Baz() : foo(bar) {}
// or get rid of "bar" entirely and do this
Baz(bool) : foo(4,5,6) {}
};
Three Baz::bar(4,5,6);
int main() {
Baz z;
std::cout << z.foo[1].x << "\n";
}
z.foo isn't actually an array, but it looks about as much like one as a vector does. Adding begin() and end() functions to Three is trivial.
Only the default constructor can be called when creating objects in an array.
In the specific case when the array is a data member of the class you can't initialize it in the current version of the language. There's no syntax for that. Either provide a default constructor for array elements or use std::vector.
A standalone array can be initialized with aggregate initializer
Foo foo[3] = { 4, 5, 6 };
but unfortunately there's no corresponding syntax for the constructor initializer list.
There is no array-construction syntax that ca be used in this context, at least not directly. You can accomplish what you're trying to accomplish by something along the lines of:
Bar::Bar()
{
static const int inits [] = {4,5,6};
static const size_t numInits = sizeof(inits)/sizeof(inits[0]);
std::copy(&inits[0],&inits[numInits],foo); // be careful that there are enough slots in foo
}
...but you'll need to give Foo a default constructor.
Ideas from a twisted mind :
class mytwistedclass{
static std::vector<int> initVector;
mytwistedclass()
{
//initialise with initVector[0] and then delete it :-)
}
};
now set this initVector to something u want to before u instantiate an object. Then your objects are initialized with your parameters.
You can do it, but it's not pretty:
#include <iostream>
class A {
int mvalue;
public:
A(int value) : mvalue(value) {}
int value() { return mvalue; }
};
class B {
// TODO: hack that respects alignment of A.. maybe C++14's alignof?
char _hack[sizeof(A[3])];
A* marr;
public:
B() : marr(reinterpret_cast<A*>(_hack)) {
new (&marr[0]) A(5);
new (&marr[1]) A(6);
new (&marr[2]) A(7);
}
A* arr() { return marr; }
};
int main(int argc, char** argv) {
B b;
A* arr = b.arr();
std::cout << arr[0].value() << " " << arr[1].value() << " " << arr[2].value() << "\n";
return 0;
}
If you put this in your code, I hope you have a VERY good reason.
This is my solution for your reference:
struct Foo
{
Foo(){}//used to make compiler happy!
Foo(int x){/*...*/}
};
struct Bar
{
Foo foo[3];
Bar()
{
//initialize foo array here:
for(int i=0;i<3;++i)
{
foo[i]=Foo(4+i);
}
}
};
in visual studio 2012 or above, you can do like this
struct Foo { Foo(int x) { /* ... */ } };
struct Baz {
Foo foo[3];
Baz() : foo() { }
};
class C
{
static const int myARRAY[10]; // only declaration !!!
public:
C(){}
}
const int C::myARRAY[10]={0,1,2,3,4,5,6,7,8,9}; // here is definition
int main(void)
{
C myObj;
}
Related
I want to explicitly change the second parameter in a constructor of a struct, in the following scenario. Is it possible, if so, how?
struct foo{
int x;
int y;
foo(int a=4, int b=6){
x=a;
y=b;
}
};
int main(){
foo *f = new foo();
cout<<f->x<<" "<<f->y<<endl;
//4 6
foo *g = new foo(3,4);
cout<<g->x<<" "<<g->y<<endl;
//3 4
foo *h = new foo(3);
cout<<h->x<<" "<<h->y<<endl;
//3 6
//Can something like this be
//done in C++, if I want
//to change the value of the
//second variable only
foo *k = new foo(b = 13);
return 0;
}
Is it possible, if so, how?
It is not possible with constructor. In general, c++ does not support named keyword arguments to functions, and it is not possible to skip arguments even if they have a default, if you want to pass a non-default after it.
It will be possible without constructor using list initialisation syntax since C++20 using designated initialisers, if you use default member initialisers:
struct foo{
int x = 4;
int y = 6;
};
int main(){
foo f {.y = 4};
}
You can achieve something similar with tag dispatching; No need for future standard:
struct foo{
int x = 4;
int y = 6;
enum Xtag { Xinit };
enum Ytag { Yinit };
foo(int a, int b) : x(a), y(b) {}
foo(Xtag, int a) : x(a) {}
foo(Ytag, int b) : y(b) {}
};
int main(){
foo f(foo::Yinit, 4);
}
A solution using lambda that can be used without modifying an existing class. Following works with your definition of foo:
auto make_foo_x4 = [](int b) {
return foo(4, b);
};
foo f = make_foo_y(4);
The downside is that we have to explicitly repeat the default value of x, so this can break assumptions if the default is changed in class definition.
Consider the following class hierarchy, made from aggregates:
struct Foo {
int k;
double d;
};
struct Bar : Foo {
int i;
};
Now, let's say I would like to initialize an object of type Bar from an object of type Foo, giving extra argument for i. (For reason to dull to discuss here, adding a constructor to Bar which accept Foo and int, or modifying definition of Bar or Foo in any other way is out of question). In C++17 I would use aggregate initialization:
auto make(const Foo& f) {
return Bar{f, 42};
}
This is not available in C++14. Is there anything else I can do mimic desired behavior in C++14? I am trying to avoid something like
auto make(const Foo& f) {
Bar b;
b.k = f.k;
b.d = f.d;
b.i = 42;
return b; // or return Bar{f.k, f.d, 42};
}
Where the thing I am trying to avoid is making make aware of internals of Foo - i.e. make is fine to know how to initialize extra members of Bar, but would prefer not to initialize members of Bar which are common with Foo.
auto make(const Foo& f) {
Bar b;
static_cast<Foo&>(b) = f;
b.i = 42;
return b;
}
I have the following class:
//in some .h file
#define BARS_IN_FOO 5 //The only place where this number should be specified.
//All code should work when I change this
//in some .cpp file
struct Foo;
struct Bar { Foo & foo; Bar(Foo & foo) : foo{ foo } {} } //Cannot be default initialized
struct Foo {
std::array<Bar, BARS_IN_FOO> myBars;
Foo() :
myBars{ } //Error. Cannot default initialize Bars.
//I want to initialize all Bars with Bar{*this} but at this point I don't
//know how many Bar initializers I should put in the myBar initializer list
{}
}
So how should I initialize Foo::myBars? The number of Bars is known at compile time but I just want to specify this number in one place (in the define preferably, other suggestions are welcome).
Usage of Foo::mybars:
Size of it will never change during runtime but I haven't decided what the number will be yet but will be somewhere in the range [1..10] (or so) (number might change a lot during development).
Element values will never change
(always will be the same non-const objects).
Relation ship between Foo and Bar is that of composition. A Foo is made out of Bars and their lifetime is the same. Bar without a Foo and visa versa makes no sense.
The Foo and Bar classes are part of performance critical code and their size will influence the memory footprint of the program a lot (80-90% of the memory footprint will be Foos and Bars).
Compiler: MSVS2017 version 15.3
Edit: Changing std::array<Bar, BARS_IN_FOO> myBars; to Bar myBars[BARS_IN_FOO]; is also oke if this helps.
Important edit: All the ctors of Bar and Foo are public. This was a mistake. I changed this.
You can do this pretty easily if you can assume that Bar is movable/copyable:
template <std::size_t ... Is>
std::array<Bar, sizeof...(Is)> make_bar_array_impl(Foo& f, std::index_sequence<Is...>) {
return { (Is, f)... };
}
template <std::size_t N>
std::array<Bar, N> make_bar_array(Foo& f) {
return make_bar_array_impl(f, std::make_index_sequence<N>{});
}
Foo() : myBars(make_bar_array<BARS_IN_FOO>(*this)) {}
This could easily refactored to use a more generic template metaprogramming utility of "repetition". I suspect that any template meta programming library will have some such utility, here I don't bother factoring it out since it is a one liner anyhow. But if you come across such problems often it's something to consider (just write a function that returns an N-entry initializer list all with the same expression).
Live example: http://coliru.stacked-crooked.com/a/aab004c0090cc144. Sorry couldn't easily access an MSVC compiler. Also compiled with 14 since I didn't need any 17 features.
Edit: even if Bar is not movable/copyable, or if you don't think things will get optimized, this technique can actually be modified to work even in that case. You can generate an array<std::reference_wrapper<Foo>, N instead. But this is a little bit more complex and typically in C++ most things should be movable, and usually constructor calls are not in the critical path. Still I can elaborate if necessary.
Edit2: also, please don't use a #define for that. constexpr static auto BARS_IN_FOO = 5; should work exactly the same way, except that it is properly namespaced (and probably some other macro nastiness I'm forgetting).
The solution is to build a char array (or a byte array in C++ 17) and use a pointer from there to have a Bar array. An union with a single Bar is enough to ensure proper alignment:
#include <iostream>
#define BARS_IN_FOO 5
// X is the type of the "array", Y the type of its initializer, n the size
template<class X, class Y = X, int n = 1>
class InitArr {
union {
X initial; // guarantee correct alignment
char buffer[n * sizeof(X)]; // only to reserve enough place
};
public:
InitArr(Y& inival): initial(inival) {
for (int i = 0; i < n; i++) {
new(&initial + i)X(inival); // properly construct an X at &initial +i
// which is guaranteed to be inside buffer
}
}
X& operator[] (int i) { // make InitArr behave like an array
X* arr = &initial;
return arr[i]; // could add control that 0 <= i < n
}
};
struct Foo;
struct Bar { Foo & foo; Bar(Foo & foo) : foo{ foo } {} }; //Cannot be default initialized
struct Foo {
InitArr<Bar, Foo, BARS_IN_FOO> myBars;
Foo() :
myBars{ *this }
//I want to initialize all Bars with Bar{*this}
{}
};
int main() {
Foo foo;
std::cout << &foo << std::endl;
// shows that all foo.myBars[i] point to the original foo
for (int i = 0; i < BARS_IN_FOO; i++) {
std::cout << &(foo.myBars[i].foo) << std::endl;
}
return 0;
}
As the X are constructed in place, everything is acceptable for any C++11 compiler and you get a true random access container. There is no Undefined Behaviour, because the memory was reserved by the char array, and the objects are correctly constructed there. This is a generic trick to delay a complex member initialization inside the constructor with the full power of the language, when thing become hard to do with a mere initializer or with compile time meta-programming.
Here is my original idea left here for reference but really less nice...
You could try to build a custom recursive array, to allow initialization of all of its elements from the same value:
// X is the type of the "array", Y the type of its initializer, n the size
template<class X, class Y=X, int n = 1>
class RArr {
public:
X first;
RArr<X, Y, n-1> other;
RArr(Y& i) : first(i), other(i) {}
X& operator [] (int i) {
if (i >= n || i < 0) throw std::domain_error("Out of range");
if (i == 0) return first;
return other[i - 1];
}
};
// specialization for n=1
template <class X, class Y>
class RArr<X, Y, 1> {
public:
X first;
RArr(Y& i) : first(i) {}
X& operator [] (int i) {
if (i != 0) throw std::domain_error("Out of range");
return first;
}
};
struct Foo;
struct Bar { Foo & foo; Bar(Foo & foo) : foo{ foo } {} }; //Cannot be default initialized
struct Foo {
RArr<Bar, Foo, BARS_IN_FOO> myBars;
Foo() :
myBars{ *this }
//I want to initialize all Bars with Bar{*this}
{}
};
int main() {
Foo foo;
std::cout << &foo << std::endl;
// shows that all foo.myBars[i] point to the original foo
for (int i = 0; i < BARS_IN_FOO; i++) {
std::cout << &(foo.myBars[i].foo) << std::endl;
}
return 0;
}
Well it works as per your requirements but is pretty useless as is because all the Bar elements refere to the same Foo. It will only make sense when Bar class will contain other members.
Does making a constructor having multiple arguments explicit have any (useful) effect?
Example:
class A {
public:
explicit A( int b, int c ); // does explicit have any (useful) effect?
};
Up until C++11, yeah, no reason to use explicit on a multi-arg constructor.
That changes in C++11, because of initializer lists. Basically, copy-initialization (but not direct initialization) with an initializer list requires that the constructor not be marked explicit.
Example:
struct Foo { Foo(int, int); };
struct Bar { explicit Bar(int, int); };
Foo f1(1, 1); // ok
Foo f2 {1, 1}; // ok
Foo f3 = {1, 1}; // ok
Bar b1(1, 1); // ok
Bar b2 {1, 1}; // ok
Bar b3 = {1, 1}; // NOT OKAY
You'd stumble upon it for brace initialization (for instance in arrays)
struct A {
explicit A( int b, int c ) {}
};
struct B {
B( int b, int c ) {}
};
int main() {
B b[] = {{1,2}, {3,5}}; // OK
A a1[] = {A{1,2}, A{3,4}}; // OK
A a2[] = {{1,2}, {3,4}}; // Error
return 0;
}
The excellent answers by #StoryTeller and #Sneftel are the main reason. However, IMHO, this makes sense (at least I do it), as part of future proofing later changes to the code. Consider your example:
class A {
public:
explicit A( int b, int c );
};
This code doesn't directly benefit from explicit.
Some time later, you decide to add a default value for c, so it becomes this:
class A {
public:
A( int b, int c=0 );
};
When doing this, you're focussing on the c parameter - in retrospect, it should have a default value. You're not necessarily focussing on whether A itself should be implicitly constructed. Unfortunately, this change makes explicit relevant again.
So, in order to convey that a ctor is explicit, it might pay to do so when first writing the method.
Here's my five cents to this discussion:
struct Foo {
Foo(int, double) {}
};
struct Bar {
explicit Bar(int, double) {}
};
void foo(const Foo&) {}
void bar(const Bar&) {}
int main(int argc, char * argv[]) {
foo({ 42, 42.42 }); // valid
bar({ 42, 42.42 }); // invalid
return 0;
}
As you can easily see, explicit prevents from using initializer list alongside with bar function bacause the constructor of struct Bar is declared as explicit.
I know that you can initialize structs using list syntax:
struct Foo f = {a, b, c};
return f;
Is it possible to do this in one line as you would with classes and constructors?
If you want your struct to remain a POD, use a function that creates it:
Foo make_foo(int a, int b, int c) {
Foo f = { a, b, c };
return f;
}
Foo test() {
return make_foo(1, 2, 3);
}
With C++0x uniform initialization removes the need for that function:
Foo test() {
return Foo{1, 2, 3};
// or just:
return {1, 2, 3};
}
Create a constructor for the struct (just like a class) and just do
return Foo(a,b,c);
Edit: just to clarify: structs in C++ are just like classes with the minor difference that their default access-permission is public (and not private like in a class). Therefore you can create a constructor very simply, like:
struct Foo {
int a;
Foo(int value) : a(value) {}
};