I believe that anything uninitialized gets automatically initialized and that this is somewhat dangerous (and poor practice). I also understand that initialization lists are generally more efficient (and in some cases necessary), however, I wanted to verify some parameters via a function call, before assigning them to a member variable.
For example, using the typical assignment constructor, I'd have something like this:
class MyObj
{
private:
int one_;
int two_;
DiffObj diffObj_;
... // other stuff
}
MyObj::MyObj(int a, int b, std::string type, std::vector<double> params)
{
one_ = a;
two_ = b;
if (verifyType(type, params))
{
diffObj_ = createDiffObj(params);
}
}
With this situation though, how could I utilize an initialization list? I thought perhaps by initializing some of the parameters in the constructor and using a separate call to initialize the rest, but I am not quite sure if that is kosher.
MyObj::MyObj(int a, int b) :
one_(a),
two_(b)
{}
MyObj::initializeDiffObj(std::string type, std::vector<double> params)
{
if (verifyType(type, params))
{
diffObj_ = createDiffObj(params);
}
}
Something like this would be perfectly reasonable. You can have an initializer-list and do some work inside your constructor, you do not have to pick one.
class MyClass {
public:
MyClass(int a, SomeStruct b)
: _a(a) {
if (isValid(b)) {
// Initialize _b
_b = createWeirdThingFromSomeStruct(b);
}
}
private:
int _a;
WeirdThing _b;
};
If your constructor does not provide an initializer for a member, that member is default-initialized. For int that means no initialization at all; for class types with a user-provided constructor it means to call that constructor.
Ideally the constructor-initializer list should do all the initializing of members. Here is one way to do it for your situation:
MyObj::MyObj(int a, int b, std::string type, std::vector<double> params)
: one_(a), two_(b),
diffobj( verifyType(type, params), std::move(params) )
{
}
This (ab)uses the comma operator to fit in the call to verifyType during the initialization of diffobj. The verifyType function should throw an exception if verification fails.
Related
I have a std:array something like this:
class MyClass {
private:
std::array<MyComplexType, 10> myArray;
}
In the constructor, I need to do the following:
MyClass::MyClass() : myArray({
MyComplexType(func(const_arg1, const_arg2, const_arg3).method(const_arg4)),
... repeated 8 more times...
MyComplexType(func(const_arg1, const_arg2, const_arg3).method(const_arg4))
})
Now, I want the 10 to be a compile-time constant that I can modify without having to copy&paste more (or less) of those initializers. They are all the same, I just need a "repeat n times". Everything up to and including C++17 is fair game.
I am 99.9% certain this should be doable with some template magic, but so far I came up with nothing that worked. Any ideas?
(And if it is impossible with templates, maybe with macros? Though I would hate having to go that direction...)
If you want to use a std::array you are going to need to build a helper function, namely a delegating constructor. Your default constructor will then call the delegate to actually initialize the member. That can look like
class MyClass {
public:
// default c'tor, create sequence of 10 integers
MyClass() : MyClass(std::make_index_sequence<10>{})
private:
// delegate, take a sequence and expand the initializer of myArray sizeof...(Is) times
template <std::size_t... Is>
MyClass(std::index_sequence<Is...>) :
myArray{ (Is, MyComplexType(func(const_arg1, const_arg2, const_arg3).method(const_arg4)))... } {}
std::array<MyComplexType, 10> myArray;
}
You can instead change myArray to be a vector instead and that would let you simplify the code to
class MyClass {
public:
MyClass() :
myData(MyComplexType(func(const_arg1, const_arg2, const_arg3).method(const_arg4)), 10) {}
private:
std::vector<MyComplexType> myData;
}
You could wrap the type into another struct/class which would provide an appropriate default constructor:
int f(int n)
{
return n;
}
struct S
{
S(int n) : n(n) { }
int n;
};
class MyClass
{
struct Wrapper
{
S s;
Wrapper() : s(f(7)) {}
};
std::array<Wrapper, 10> myArray;
};
You're now delegating the initialisation to the wrapper.
You might yet invest some work makeing the need of explicit indirection (myArray[i].s) obsolete, e.g. wrapping the array itself into another struct/class, too, providing the same interface as a std::array (as far as you need at least…) but with its iterators and index operators dereferencing to the complex type instead of to the wrapper (i.e. your iterator wraps around an array's iterator with S& operator*() { return i->s; } S* operator->() { return &i->s; } and further operators like increment just delegating to the wrapped iterator).
Given an immutable C++ object (its members are const, which means its operator=() method does not exist), how do you implement this simple procedural pattern (which would require Object::operator=() to exist):
Object someObject {17};
// ...
if (...) {
someObject = Object {42};
}
// ...
use(someObject);
A workaround is to use shared_ptr.
shared_ptr<Object> someObject(new Object(17));
shared_ptr<Object> anotherObject(new Object(42));
// ...
if (...) {
someObject = anotherObject;
}
use(someObject);
My pattern in such a situation is to extract initialization code into a function:
Object ini(...){
if(...) {
return Object{42};
}
return Object{17};
}
.....
Object someObject=ini(...);// copy constructor used (or not, because of RVO)
use(someObject);
If initialization is simple you could use:
Object someObject = ...? Object{42} : Object{17};
It is not very different to declaring your o-variable const.
If the someObject=17 is used and then replaced with someObject=42 - it's just undermining the good intentions which were pursued by declaring some members const.
There are two alternatives:
declaring some members const was not such bright idea - it can be undone and an assigment operator can be added.
using Object as it was meant to be used.
What should not be done lightly: making some tricks with pointers/references - it will just make your code more complex as it is. Better to use a new variable if needed:
Object someObject {17};
// ...
Object newSomeObject = ... ? Object {42} : someObject {17};
use(newSomeObject);
In the case that copying of the old object could be a performance problem, the code can be refactored in such a way, that
use(need42(..) ? create42() : object17);
can be used without copying data. This solution assumes that use uses a const reference of its argument or the parameter is passed by-value.
In my opinion every change of an immutable object should yield a new object, otherwise, the following can happen:
ImmutableObject obj(1);
ImmutableObject &ref=obj;//ref.member=1
...
obj=ImmutableObject(2);
//ref.member!=1, that is puzzling, I assumed ref to be immutable!
Now, the user of your object (via ref) gets irritated because the object was changed! The whole point of the immutability is that you can reason, that the values never ever change. If they can change, there is not that many advantages in using "immutables" in the first place.
The other answers work when your initialization logic may be simple, but if you're detangling some spaghetti code, this might help.
If it isn't, take from java (they might not have invented it, but I see java programmers use this most) -- the builder pattern. Here are two possible ways of implementing it in C++.
#include <string>
class ImmutableClass {
public:
ImmutableClass(int a, int b, std::string c) : a_(a), b_(b), c_(c) {}
// Getters...
private:
ImmutableClass& operator=(const ImmutableClass&) = delete;
const int& GetA() {return a_;}
const int& GetB() {return b_;}
const std::string& GetC() {return c_;}
const int a_;
const int b_;
const std::string c_;
};
struct ImmutableClassBuilderExampleOne {
public:
// Note the default initialization to avoid undefined behavior.
int a = 0;
int b = 0;
std::string c;
};
// Less boilerplate, less encapsulation, if that's your thing.
ImmutableClass BuildImmutableClass(const ImmutableClassBuilderExampleOne& icb) {
return ImmutableClass(icb.a, icb.b, icb.c);
}
// More boilerplate, more encapsulation, can be "tidied" with macros.
class ImmutableClassBuilderExampleTwo {
public:
const ImmutableClass build() {
return ImmutableClass(a_, b_, c_);
}
ImmutableClassBuilderExampleTwo& setA(const int a) {
a_ = a;
return *this;
}
ImmutableClassBuilderExampleTwo& setB(const int b) {
b_ = b;
return *this;
}
ImmutableClassBuilderExampleTwo& setC(const std::string& c) {
c_ = c;
return *this;
}
private:
// Note the default initialization to avoid undefined behavior.
int a_ = 0;
int b_ = 0;
std::string c_;
};
A library which I can't modify has a type akin to the following:
class A {
public:
A () : A(0) { }
explicit A (int const value) : value_(value) { }
A (A const &) = delete;
A (A &&) = delete;
A & operator= (A const &) = delete;
A & operator= (A &&) = delete;
private:
int value_;
}
Now, I have a class which requires a bunch of As as members. Due to other restrictions of the environment I'm working in all of these As must either be separate members or a member array (i.e. I can't use an std::vector to put them in or create pointers to them). I.e. my class boils down to this:
struct Foo {
A a[2];
}
Is there any way to initialize each member with a distinct initial value? I've been trying various forms of using braced-list initialization, but they all fail due to either A(int) being explicit or A not having a copy/move-constructor.
What doesn't work:
Foo () : A{ { 1 }, { 2 } } { }: won't call A(int) since it's explicit.
Foo () : A{ { A(1) }, { A(2) } } { }: can't copy- nor move-assign.
Edit: Updated info about member array requirement.
Edit 2: The library in question is SystemC. My example class A is a port (e.g. sc_core::sc_in).
The reason I can't use an array of pointers is because, as far as I know, Mentor Graphic's Questa can't really deal with them. It will simulate the model correctly, but won't allow inspection of the ports. I.e. it won't be able to plot the port's values over time in a wave window. I would be very happen to be proven wrong about this, because that would allow a trivial solution to my problem.
Edit 3: Apparently this is a big issue anymore in a newer version of Questa. I'm not sure what changed between seeing this problem and now, could be a change to the development environment as well (which is also out of my control). In any case, my Questa now automatically names ports after their variable name (unless explicitly renamed at construction), so all is well.
Just for the sake knowing how to I'd still like to see potential solutions to the original problem though.
struct Foo {
A a[2];
}
Is there any way to initialize each member with a distinct initial
value? I've been trying various forms of using braced-list
initialization, but they all fail due to either A(int) being
explicit or A not having a copy/move-constructor.
You may need to use placement-new to create an array of A in some raw storage array. You then create a std::initializer_list<ARGUMENT> of the ARGUMENTs needed to construct each A. Something like:
template<typename T, std::size_t Size, std::size_t Alignment = alignof(T)>
struct FixedArray{
std::aligned_storage_t<sizeof(T), Alignment> data[Size];
static constexpr std::size_t size = Size;
template<typename U>
FixedArray(std::initializer_list<U> ls){
assert(ls.size() <= Size && "Invalid Size"); int index = 0;
for(auto& x : ls)
new (&data[index++]) T(x);
}
FixedArray(const FixedArray&) = delete;
FixedArray(FixedArray&&) = delete;
A& operator[](std::size_t index){
auto ptr = reinterpret_cast<A*>(&data) + index;
return *std::launder(ptr); //Sort of a legal way to alias memory C++17
}
~FixedArray(){
for(std::size_t i = 0; i < size; i++)
this->operator[](i).~T();
}
};
Then declare Foo:
struct Foo {
FixedArray<A, 4> a;
};
To create Foo having A(546), A(99), A(-4), A(0):
int main() {
Foo f{{546, 99, -4, 0}};
return 0;
}
See a working Demo
After testing with GCC 6.3 at -O3 optimization levels, about exactly the same assembly is generated for using FixedArray vs plain raw arrays, See it on gcc.godbolt.com.
I am able to solve the problem as follows (also using SystemC, here my non-copyable, non-movable items are sc_modules):
class Object : sc_module {
Object(sc_module_name name){}
};
class Container : sc_module {
std::array<Object, 3> objects;
Container(sc_module_name name) :
objects{{{"object1"},{"object2"},{"object3"}}}
{}
};
The short answer - no. The longer answer - kind of, but its disgusting.
Take a look at this discussion.
Like if I have this structure:
struct S
{
S(const S &arg) : (arg.bIsDouble ? v1{arg.v1} : v{arg.v}) {}
bool bIsDouble{false};
union {
vector<int> v;
double v1;
};
} ;
How can I make the copy constructor to either initialize 'v' or 'v1' based on some condition?
I would just outsource your work to Boost.Variant:
struct S {
S(const S&) = default;
boost::variant<double, std::vector<int> > v;
};
If you don't want to use Boost, you can read about how to write a discriminated union here, and then implement your own.
Since you only need two types, that's not too complicated, although it's still very error prone and involves a lot of code:
struct DoubleOrVector {
bool is_double;
static constexpr std::size_t alignment_value = std::max(alignof(double), alignof(std::vector));
alignas(alignment_value) char storage[std::max(sizeof(double), sizeof(std::vector))];
DoubleOrVector(double v)
: is_double(true)
{
new (storage) double(v);
}
// similar for vector
DoubleOrVector(const DoubleOrVector& dov)
: is_double(dov.is_double)
{
if (is_double) {
new (storage) double(dov.asDouble());
}
else {
new (storage) std::vector<int>(dov.asVector());
}
}
double& asDouble() {
assert(is_double);
return *reinterpret_cast<double*>(storage);
}
std::vector<int>& asVector() {
assert(!is_double);
return *reinterpret_cast<std::vector<int>*>(storage);
}
// plus other functions here
// remember to explicitly call ~vector() when we need to
};
And then we're still defaulting our copy ctor:
struct S {
S(const S&) = default;
DoubleOrVector v;
};
Constructor initialization list won't help here.
You have to use placement new in the class constructor, and then destroy (by manually calling the destructor) the correct member in the destructor. Also, since you define the destructor, you should define or delete the rest of The Big Five.
Minimal code:
struct S
{
bool bIsDouble{false};
union {
vector<int> v;
double v1;
};
S(bool d) : bIsDouble(d)
{
if(!bIsDouble)
new(&v) vector<int>();
// no need to create or destroy a double, since it is trivial
}
~S()
{
if(!bIsDouble)
v.~vector<int>();
}
// the other Big Five members are implicitly deleted
// so no copying, unless you write it yourself.
};
Note that switching between types is harder: if you had used the vector, and now want to use double, you need to destroy the vector first. I recommend to hide the data behind the accessor functions to enforce the invariant.
...or just use boost::variant. It's way simpler and less bug-prone.
I find it sometimes annoying that I have to initialise all POD-types manually. E.g.
struct A {
int x;
/* other stuff ... */
A() : x(0) /*...*/ {}
A(/*..*/) : x(0) /*...*/ {}
};
I don't like this for several reasons:
I have to redo this in every constructor.
The initial value is at a different place than the variable declaration.
Sometimes the only reason I have to implement a constructor is because of this.
To overcome this, I try to use my own types instead. I.e. instead of using int x,y;, I use my own vector struct which also initialize automatically with 0. I also thought about just implementing some simple wrapper types, like:
template<typename T>
struct Num {
T num;
Num() : num(0) {}
operator T&() { return num; }
operator const T&() const { return num; }
T& operator=(T _n) { num = _n; return num; }
/* and all the other operators ... */
};
This basically solves this so far for all cases where I want to init with 0 (that are by far the most often cases for me).
Thanks to James McNellis for the hint: This can also be solved via the boost::value_initialized.
Now, not limited to POD-types:
But sometimes I want to initialise with something different and there are the troubles again because that Num template struct cannot easily be extended to allow that. Basically because I cannot pass floating point numbers (e.g. float) as a template parameter.
In Java, I would just do:
class A {
int x = 42;
/*...*/
public A() {}
public A(/*...*/) { /*...*/ }
public A(/*...*/) { /*...*/ }
/*...*/
}
I find it quite important that in such cases where you want to init a member variable always in the same way in all possible constructors, that you are able to write the init value directly next to the member variable, like in int x = 42;.
So the thing I was trying to solve is to do the same thing in C++.
To overcome the problem that I cannot pass the init-value via a template parameter, I hacked together an ugly macro:
#define _LINENAME_CAT( name, line ) name##line
#define _LINENAME( name, line ) _LINENAME_CAT( name, line )
/* HACK: use _LINENAME, workaround for a buggy MSVC compiler (http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=360628)*/
#define PIVar(T, def) \
struct _LINENAME(__predef, __LINE__) { \
typedef T type; \
template<typename _T> \
struct Data { \
_T var; \
Data() : var(def) {} \
}; \
Data<T> data; \
T& operator=(const T& d) { return data.var = d; } \
operator const T&() const { return data.var; } \
operator T&() { return data.var; } \
}
(For other compilers, I can just omit that _LINENAME name for the struct and just leave it unnamed. But MSVC doesn't like that.)
This now works more or less like I want it. Now it would look like:
struct A {
PIVar(int,42) x;
/*...*/
A() {}
A(/*...*/) { /*...*/ }
A(/*...*/) { /*...*/ }
/*...*/
};
While it does what I want (mostly), I still am not fully happy with it:
I don't like the name PIVar (which stands for PreInitVar) but I really couldn't come up with something better. At the same time, I want to have it short.
I don't like that macro hack.
How have you solved this? Any better solution?
There was an answer which was deleted again which said that C++0x allows basically the same syntax as in Java. Is that true? So then I would just have to wait for C++0x.
Please don't give any comments like:
"then just use Java instead" / "don't use C++ then" or
"if you need something like this, you are probably doing something wrong" or
"just don't do it this way".
Also, please don't tell me not to use it. I know about all the drawbacks of my current solution. Please only make comments about non-obvious drawbacks if you are really sure that I am not aware of that. Please don't just state that there are many drawbacks in my current solution. Please also don't state that it is not worse to use it. I am just asking if you know about a better solution than the one I have presented here.
Sometimes the only reason I have to implement a constructor is because of this.
You don't have to do that.
struct POD {
int i;
char ch;
};
POD uninitialized;
POD initialized = POD();
Equally in an initialization list:
class myclass
POD pod_;
// ....
myclass()
: pod_() // pod_'s members will be initialized
{
}
To overcome this, I try to use my own types instead.
Your type fails in this scenario:
void f(int&);
Num<int> i;
f(i);
There's likely more problems, but this is what occurred to me immediately.
How have you solved this? Any better solution?
Yes, we all have solved this. We did by not attempting to fight the language, but to use it the way it was created: initialize PODs in initialization lists. When I see this:
struct ML_LieroX : MapLoad {
std::string id;
PIVar(int, 0) type;
std::string themeName;
PIVar(int, 0) numObj;
PIVar(bool,false) isCTF;
I cringe. What is this doing? Why is it this way? Is this even C++?
All this just to save a few keystrokes typing an initialization list? Are you even serious?
Here's an old bon mot: A piece of code gets written once, but over its lifetime will be read tens, hundreds, or even thousands of times. That means that, in the long run, the time it takes to write a piece code is more or less neglectable. Even if it takes you ten times as long to write the proper constructors, but it saves me 10% of the time necessary to understand your code, then writing the constructors is what you should do.
Boost provides a value_initialized<T> template that can be used to ensure an object (POD or not) is value-initialized. Its documentation goes into great detail explaining the pros and cons of using it.
Your complaint about not being able to automatically initialize an object to a given value doesn't make much sense; that has nothing to do with the object being POD; if you want to initialize a non-POD type with a non-default value, you have to specify the value when you initialize it.
You could initialize POD structures as follows:
struct POD
{
int x;
float y;
};
int main()
{
POD a = {}; // initialized with zeroes
POD b = { 1, 5.0f }; // x = 1, y = 5.0f
return 0;
}
There is a proposal for C++0x which allows this:
struct A {
int x = 42;
};
That is exactly what I want.
If this proposal is not making it into the final version, the possibility of delegating constructors is another way of at least avoiding to recode the initialization in every single constructor (and at the same time avoiding a dummy helper function to do this).
In current C++, there does not seem to be any better way to do it despite what I have already demonstrated.
C++ does have constructor delegation, so why not use it?
struct AState
{
int x;
AState() : x(42) {}
};
class A : AState
{
A() {}
A(/*...*/) { /*...*/ }
A(/*...*/) { /*...*/ }
};
Now initialization of x is delegated by all constructors. The base constructor can even accept arguments passed from each version of A::A.
Prior to C++0x there is a solution which works well if the non-zero value you want to initialize with is not completely arbitrary (which is usually the case in practice). Similar to boost::initialized_value but with an extra argument to take the initial value (which gets a little fussy because C++).
template<typename T> struct Default { T operator()() { return T(); } };
template<typename T, T (*F)()> struct Call { T operator()() { return F(); } };
template<int N> struct Integer { int operator()() { return N; } };
template< typename X, typename Value = Default<X> >
class initialized {
public:
initialized() : x(Value()()) {}
initialized(const X& x_) : x(x_) {}
const X& get() const { return x; }
operator const X&() const { return x; }
operator X&() { return x; }
private:
X x;
};
You might use it like this:
struct Pi { double operator()() { return 3.14; } }; //Exactly
const char* init_message() { return "initial message"; }
Point top_middle() { return Point(screen_width()/2, 0); }
struct X {
initialized<int> a;
initialized<int, Integer<42> > b;
initialized<double> c;
initialized<double, Pi> d;
initialized<std::string> e;
initialized<std::string, Call<const char*, init_message> > f;
initialized<Point> g;
initialized<Point, Call<Point,top_middle> > h;
X() {}
};
I find the annoyance of having to create a dummy function to return any non-integral / non-default value is generally amortized across the entire library (since the non-zero initial values for a particular type are generally shared by many classes).
Obviously typedef is a friend here.
Anyway, can't wait to upgrade to C++0x/11/14/whatever.