I want to make a vector in private part of a class that hold only 10 integers
but I get " syntax error 'constant' " while making this vector in the private part of class.
I know that I can use a constant array instead of vector but why I can't use vector with constant capacity in a class?
also if I make this vector in main() function every thing is fine but in the class I get this error!
class A
{
public:
// constructor
private:
std::vector<int> tests(10); // here I get error
};
Default member initializer (since C++11) doesn't support parentheses initializer, but only brace or equals initializer.
Through a default member initializer, which is simply a brace or equals initializer included in the member declaration, which is used if the member is omitted in the member initializer list
Note that for std::vector, using brace initializer might lead to effect you don't want. (e.g. std::vector<int>{10} initializes a vector with 1 element with value 10.) You can use equals initializer like
std::vector<int> tests = std::vector<int>(10);
BTW: If the size is fixed, you can use std::array instead.
std::array<int, 10> tests;
The initialization of your member variable must be in the constructor list of your class.
class A
{
public:
A(); // contructor
private:
std::vector<int> tests;
};
A::A() :
tests(10)
{
// constructor logic
}
Related
I have a class lazy_segment_tree. This is the current constructor
template<typename T>
struct lazy_segment_tree{
int n;
int H;
T base;
vector<T> segtree;
vector<T> lazytree;
T (*join)(T,T);
T (*assign)(int,T,T);
lazy_segment_tree(vector<T> &seq, T (*merge)(T,T), T (*create)(int, T,T), T defvalue){
join=merge;
assign=create;
base=defvalue;
n=seq.size();
}
};
Can't I directly make the construction parameters go to the values in the class variable?
I am not 100% sure what do you mean by 'directly'.
But in this case you should use initializer list to initialize the member variables. More on initializer lists here.
Applied to your code, the constructor would now look like this:
lazy_segment_tree(vector<T> &seq, T (*merge)(T,T), T (*create)(int, T,T), T defvalue)
: join(merge)
, assign(create)
, base(defvalue)
, n(seq.size())
{}
In your original code, all the members are first default-constructed during initialization of the class. Then, the body of the constructor is called where you use '=' to copy assign the constructor parameters.
When initializer list is used, the members are directly constructed with specified parameters.
Depending on what T might be, it may or may not make real difference. Nevertheless, initializer lists are the standard way to initialize class members and you should use it if possible.
I know I can initialize int variables in a constructor with a member initialization list, but can I initialize an enum type in an member initialization list like in the example below?
enum number{zero, one, two, three};
class Example{
int test;
number number_enum;
public:
Example(int test_arg, number number_enum_arg): test(test_arg),
number_enum(number_enum_arg){
}
};
Also, I know it is better to initialize variables using an member initialization list, rather than using the assignment operator, but exactly is that?
The code in your example will work, you can initialize enums and virtually all types in an initializer list. Add a line to your constructor to print it out, you'll see.
I'm having trouble with something that seems very easy, so I must be overlooking something.
I need to construct a class that has a field that is also a class (non-POD). The class of the field has a default constructor and a "real" constructor. The thing is that I really can't construct the field in the initializer list, because in reality the constructor has a parameter that is a vector which needs a somewhat complex for loop to fill.
Here is a minimal example that reproduces the problem.
ConstructorsTest.h:
class SomeProperty {
public:
SomeProperty(int param1); //Ordinary constructor.
SomeProperty(); //Default constructor.
int param1;
};
class ConstructorsTest {
ConstructorsTest();
SomeProperty the_property;
};
ConstructorsTest.cpp:
#include "ConstructorsTest.h"
ConstructorsTest::ConstructorsTest() {
the_property(4);
}
SomeProperty::SomeProperty(int param1) : param1(param1) {}
SomeProperty::SomeProperty() : param1(0) {} //Default constructor, doesn't matter.
But this gives a compile error:
ConstructorsTest.cpp: In constructor 'ConstructorsTest::ConstructorsTest()':
ConstructorsTest.cpp:4:19: error: no match for call to '(SomeProperty) (int)'
the_property(4);
^
It gives no suggestions like it usually would of what functions could have been intended instead.
In the above example I would just initialize the_property in the initializer list, but in reality the 4 is actually a complex vector that needs to be generated first, so I really can't. Moving the_property(4) to the initializer list causes the compilation to succeed.
Other similar threads mention that the object must have a default constructor, or that it can't be const. Both requirements seem to have been met, here.
You can't initialize data member inside the constructor's body. (the_property(4); is just trying to invoke the_property as a functor.) You can only assign them like:
ConstructorsTest::ConstructorsTest() {
the_property = ...;
}
but in reality the 4 is actually a complex vector that needs to be generated first
You can add a member function which generate the necessary data, and use it to initialize the data member in member initializer list. e.g.
class ConstructorsTest {
...
static int generateData();
};
int ConstructorsTest::generateData() {
return ...;
}
ConstructorsTest::ConstructorsTest() : the_property(generateData()) {
}
You cannot initialize a variable twice.1 When your constructor has started, all member subobjects will have been constructed. If you do not provide a member initializer in the constructor, or a default member initializer in the class definition, then it will perform default initialization. Regardless of what form it takes, you can't construct it again.
Complex multi-statement initialization is best done via a lambda function:
ConstructorsTest::ConstructorsTest()
: the_property( []{ /* Do Complex Initialization */}() )
{
}
1: Well... you can, but not like that. And you really shouldn't for cases as simple as this.
Here is a smaller version of a use case that I am working on.
#include <mutex>
template<typename T = float>
class Foo
{
public:
Foo(int x, int y):m_mutex(){}
private:
std::mutex m_mutex; // This is must have in my project
};
typedef Foo<float> Foo_typedef;
class Func
{
public:
static Foo_typedef static_array[2];
};
Foo_typedef Func::static_array[2] = { Foo_typedef(2,3), Foo_typedef(2,3) };
int main()
{
return 0;
}
After compiling this VS 2015 Update 2 emits following errors.
error C2280: 'Foo<float>::Foo(const Foo<float> &)': attempting to reference a deleted function
note: see declaration of 'Foo<float>::Foo'
I looked around and I suspected that there might one of the two reasons this.
1) Copy constructor member for std::mutex is deleted
2) This which I thought might be similar to what I am seeing.
Which one is it? What can I do to bypass this error thrown by VS 2015 Update 2 compiler?
UPDATE:Updated the constructor which takes in some parameters that are needed to be passed to Foo_typedef.
You need to construct the element in place using the constructor:
Foo_typedef Func::static_array[2] = { {2, 3}, {2, 3} };
With this, there are no copy or move because the two elements are constructed in place.
The standard says (ยง8.5.1/2 [dcl.init.aggr], emphasis is mine):
When an aggregate is initialized by an initializer list, [...] the elements of the initializer list are taken as initializers for the members of the aggregate [...].
In your case, it means that Foo_typedef(2,3) will be taken as an initializer for your Foo_typedef and thus a copy will be needed. In the code I gave, {2, 3} will be taken as an initializer and the corresponding constructor will be called (no copy).
I've been programming in C++ a while and I've used both methods:
class Stuff {
public:
Stuff( int nr ) : n( nr ) { }
private:
int n;
}
Or
class Stuff {
public:
Stuff( int nr ) {
n = nr;
}
private:
int n;
}
Note: This is not the same as this, similar but not the same.
What is considered best practice?
Initializer lists are preferred. See FAQ 10.6
One big advantage to using initializers: If an exception is thrown anywhere within the initializer list, the destructors will be called for those members that had already been initialized -- and only for those members.
When you use the contructor body to initialize the object, it's up to you to handle exceptions properly and unwind the object as appropriate. This is usually much harder to get right.
Use the initializer list when possible. For an int, it doesn't matter much either way, but for a more complex member object, you'd end up with the default constructor of the object being called, followed by an assignment to that object, which is likely to end up being slower.
Plus, you have to do it that way anyway for const members or members which don't have a default constructor.
If possible, use the first version.
The first is initializing using intializer lists, and actually calls the constructors of the members.
The second is assignment. If n was of a type with a default constructor, it the would have already been called, and then you'd be assigning to it. If n didn't have a default constructor, you'd be forced to use the first type. Likewise if n was a reference: int &n.
If there are no constructors of you members that directly take one of the parameters to your constructor, it may be worthwhile to add private static functions that can do the conversion for you.
I generally try to do the initializer list when I can. For one thing, this makes it explicit that you are initializing code in the constructor. const memebers have to be initialized this way.
If you just put code in the constructor's body, it is quite possible someone may decide to come along and move a big chunk of it into a non-constructor "setup" routine later.
It can be taken overboard though. I have a coworker who likes to create classes that have 2 pages of initilizer code, no constructor code, and perhaps 2 pages for the entire rest of the class' code. I find that really tough to read.
I want to add that you don't need to declare the initializer list on the Header (.h). It can be done at the implementation of the constructor (which is very common).
So then:
//Stuff.h
class Stuff {
public:
Stuff( int nr );
private:
int n;
}
//Stuff.cpp
Stuff::Stuff(int nr)
: n(nr)
{
//initalize complex members
}
is legal and imo concentrates the initialization of fields where it matters. Sometimes we need to initialize complex members in the body, so you have your initializer list and the complex initialization all in the .cpp file.
The second option is not initialization but assignment. With types that have user defined default constructors, the second option will call the default constructor and later on call the assignment operator (whether user defined or not) to assign the value.
Some types cannot be default initialized: If you have an attribute without default constructor, hold references (constant or not) or have constant attributes they must be initialized in the initializer list.
Arrays can be value-initialized in the initialization list, but not in the constructor body:
class X {
public:
X() : array() {} // value-initializes the array
// equivalent to:
// X() { for ( int i = 0; i < 10; ++i ) array[i]=0; }
private:
int array[10];
};
For POD types, you can value-initialize them in the initialization list but not inside the brackets:
class X {
public:
X() : pod() {} // value-initializes
// equivalent to (but easier to read and subtly faster as it avoids the copy):
// X() { pod = {}; }
private:
PODType pod;
};
Finally, some classes offer functionality through the use of constructors that will be more complex (if achievable) after default construction.
class X
{
public:
X() : v(10) {} // construct a vector of 10 default initialized integers
// equivalent to:
// X() { for ( int i = 0; i < 10; ++i ) v.push_back(0); }
private:
std::vector<int> v;
};
Last, whenever they are in fact equivalent, initialization lists are more idiomatic in C++.