Declaration of a fixed-size vector within a class

Please could someone explain why A, B and D can be legitimately declared in the following code, but C can't.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <vector>
using namespace std;

vector<int> A(4,0);

class Item
{
public:
   int i = 10;
   int B[4]={0};
   vector<int> C(4,0);
};

int main()
{
   Item x;
   vector<int> D(4,0);
}
Being able to initialize the data members directly in the class body is a relatively new addition to C++. It was decided that you can only use = or {} for this purpose. I don't know exactly why () are not allowed but I suspect it is because they could be confused for function declarations.

Outside of classes, where () initialization is allowed, the difference between a variable definition and a function declaration can be subtle.
1
2
3
4
5
int a; // variable
int b(); // function
int c(a); // variable
int d(int(a)); // function
int e(int{a}); // variable 
Last edited on
Thanks @Peter87.

Is there any way that I can initialise it with "4 lots of 0"? The only way that worked within the class seemed to be
vector<int> C = vector<int>( 4, 0 );
Outside of the class there is no problem.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <vector>
using namespace std;

vector<int> A(4,0);

class Item
{
public:
   int i = 10;
   int B[4]={0};
   vector<int> C = vector<int>( 4, 0 );
};

int main()
{
   Item x;
   vector<int> D(4,0);
   for ( auto e : x.C ) cout << e;
}

I think the way you have found is the correct way if you don't want to explicitly initialize the vector in the constructor.
 
vector<int> C = vector<int>(4);


Another option is to use {} initialization and list all the values, but this is only suitable if the number of elements are low.
 
vector<int> C {0, 0, 0, 0};


If the size is known at compile time you could consider using std::array instead of std::vector.
1
2
array<int, 4> C {}; // It's important to use {} here otherwise the
                    // elements will not be zero-initialized. 
Last edited on
But why not use the constructor?
1
2
3
4
5
6
	vector<int> C;
	Item() {
		C.resize(4);
		for (auto i : C)
			i = 0;
	}


I mean.. constructors were made specifically for initializing right. ^_^
@Peter87: Thank-you for that. Given that I couldn't do what I had expected to do, declaring as
vector<int> C;
and then putting
C = vector<int>(4, 0);
in the constructor seems most natural. However, it's a shame that it doesn't work in the same way as outside the class.

Thank-you anyway.



Grime wrote:
constructors were made specifically for initializing right. ^_^

Yes, and that's precisely why I was hoping that the vector's constructor would do what I wished. However, it didn't, inside the class.

As it happens, this is a massively-abbreviated form of a larger code, trying to isolate the particular problem. And in that larger code I didn't want things zero-initialised.
Last edited on
Just be aware that defining a constructor disables aggregate-initialization so you can no longer initialize the object as follows:

 
Item item{7, {1, 2, 3, 4}, {80}};

If your real code have the data members as private this doesn't matter because you can't do aggregate-initialization anyway in that case.


Note that the idiomatic way of initializing in the constructor would be to use the member initializer list.

1
2
3
4
5
6
Item()
:	i(10),
	B{0},
	C(4, 0)
{
}

Otherwise you would be doing default initialization followed by the code in the constructor body.

http://www.cplusplus.com/doc/tutorial/classes/#member_initialization
Last edited on
Thanks. The following works OK. (Chose to initialise C elements to 9 now, rather than the default integer value of 0.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <vector>
using namespace std;

vector<int> A(4,0);

class Item
{
public:
   int i;
   int B[4];
   vector<int> C;
   Item():i(10), B{0}, C(4,9) {}     // C initialised to 4 lots of 9 now
};

int main()
{
   Item x;
   vector<int> D(4,0);
   for ( auto e : x.C ) cout << e;
}
Last edited on
Just be aware that defining a constructor disables aggregate-initialization so you can no longer initialize the object as follows:


Huh cool I never knew that. How the heck are you so knowledgable Peter? 0_0

By the way pop question;
vector<int> C = vector<int>(4);
This would really be instantiating two vectors right? When would the vector<int>(4) go out of scope? Only when memory of class is deallocated from heap and otherwise only at program termination??
How the heck are you so knowledgable Peter? 0_0

The secret is that I spend too much time on sites like this, looking up stuff to be able to give correct answers. I'm not afraid of reading the standard if necessary. I also enjoy watching C++ talks (from CppCon, C++Now, Meeting C++, etc.) on YouTube, and listening to cppcast and cppchat. I like reading the trip reports after each standard meeting about all the new stuff that has been agreed for the next standard. I skim through the list of proposals (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/) and read about the ones that I find interesting. In the process I pick up pieces of knowledge, but don't think I know everything by heart. There are simply too many edge cases and rule changes between versions to keep track of it all. I often have to compile or look things up in order to ensure that I am correct even when I think I know something.

vector<int> C = vector<int>(4);
This would really be instantiating two vectors right? When would the vector<int>(4) go out of scope? Only when memory of class is deallocated from heap and otherwise only at program termination??

The expression that you use to initialize the member would normally create a temporary object that would get destroyed after the member has been initialized. However, in this case, when the types are the same, the compiler has always been allowed to elide the copy so that no temporary has to be created and no copying done. Compilers has been doing this kind of optimization for a long time but it was not until C++17 that it was made obligatory. In C++17 the vector wouldn't even need to have a copy or move constructor for this code to compile.
Last edited on
Thumbs up to you pal. You rock. 😊
Topic archived. No new replies allowed.