In the code below, class B has a member that is of type class A (varA1). I want to create a class B object where the member varA1 is intended to use the non-default constructor A(int v1) in class A.
#include <iostream>
using std::cout; using std::endl; using std::string;
class A {
public:
A() { cout << "A default constructor" << endl;}
A(int v1);
private:
int var1;
};
A::A(int v1) {
cout << "A int constructor" << endl;
var1 = v1;
}
class B {
public:
B() { cout << "B default constructor" << endl;}
B(int v1);
private:
int var1;
A varA1;
};
B::B(int v1) {
cout << "B int constructor" << endl;
var1 = v1;
A varA1(int v1);
}
int main()
{
A TestA(1);
B TestB(1);
return 0;
}
However when I run the code above I get the following output:
A int constructor
A default constructor
B int constructor
I must be doing some wrong here. What do I need to change so that the B class uses the non-default constructor A(int v1) in class A?
I am using ubuntu 14.04LTS. Both GNU G++ 4.9 and 5.1 gave the same results.
Thanks in advance for reading and answering.
Use a member initialization list:
B::B(int v1) : var1(v1), varA1(v1) {
cout << "B int constructor" << endl;
}
Note that members are initialized (constructed) in the same order that they're declared in the class, so switching orders in the member initialization list won't change the order in which construction happens (and hopefully your compiler will warn you of this). This little detail becomes important if you try to construct varA1 from var1 and var1 is declared after varA1 in the class definition.
And by the way, all this line does (inside the B::B(int v1) constructor):
A varA1(int v1);
is forward declare a function named varA1 that takes an int parameter and returns an A object. This is semi-similar to the most vexing parse, though this isn't really a case of the most vexing parse.
You could use an initializer list in your B::B(int) constructor:
B::B(int v1) : varA1(v1) {
cout << "B int constructor" << endl;
var1 = v1;
}
If you do not want a default ctor, you might use
A(void) = delete;
But recognize that you can temporarily add this declaration as a diagnostic measure to get the compiler to inform you for which code it wants to use the default ctor.
By replacing
A() { std::cout << "A default constructor" << std::endl;}
with
A() = delete;
The compiler will complain about the use of deleted function 'A::A()' in the body of B::B(int v1).
Thus, a brief inspection identifies that the second data attribute of B, i.e. "B::varA1", uses the default ctor of A (now deleted).
You also might consider 'fixing' the B ctor to NOT use the default ctor of A by explicitly invoking "varA1 (0)" in the initializer list of B ctor.
Related
I am recently having a problem with uniform initialization on C++14 standard. I wrote a code which declares a class having two constructors, first one is parameterized constructor and the other one is a constructor having intializer_list. The code looks as follows,
#include <iostream>
#include <vector>
class MyClass final {
public:
MyClass() = default;
explicit MyClass(const int a, const int b)
: m_a(a)
, m_b(b)
{
std::cout << "From constructor" << std::endl;
};
MyClass(std::initializer_list<int> init_li)
: m_a(init_li[0])
, m_b(init_li[1])
{
std::cout << "Initializer List constructor" << std::endl;
}
void PrintValues() const
{
std::cout << m_a << " " << m_b << std::endl;
}
private:
int m_a, m_b;
}
int
main(void)
{
using namespace std;
vector<int> a{ 1, 2 }; // Creates a vector with initializer list. Very nice.
vector<int> a{ (1, 2) }; // Calls a vector constructor "explicit vector(std::size_t __n, const std::allocator<int> &__a = std::vector<int>::allocator_type())" NOT INITIALIZER LIST constructor. Okay.
MyClass a{ 1, 2 }; // Calls the initializer list constructor. Fine.
MyClass b{ (1, 2) }; // Also calls the initializer list constructor. What???
b.PrintValues();
return 0;
}
So, my question is why can't I call a constructor other than initializer list with uniform initialization in MyClass just like I did in vector with parentheses?
This code:
MyClass a2{ (1, 2) };
could not call the 2 argument constructor. What is happening is that in the expression (1,2), the 1 is evaluated before the comma operator, it is discarded, and the result of the expression is 2. This obviously calls the initializer_list constructor.
Enable warnings, e.g. with -Wall and the compiler will tell you about this.
Note that the same thing happens in the vector<int> a{ (1, 2) }; call. The 1 is discarded, and the constructor of vector that takes a single argument is invoked.
I have the following C++ code:
#include <iostream>
struct A
{
A() { std::cout << "A" << ++x; }
A(int x) : A() { std::cout << x; }
~A() { std::cout << "D"; }
static int x;
};
int A::x = 0;
struct B
{
A a, aa, aaa;
B() : aa(1), a(2) { std::cout << "B" << std::endl; }
~B() { std::cout << "B" << A::x; }
};
B beta;
int main()
{
return 0;
}
I understand everything in the control flow except of destructor calls.
Here is the control flow without destructors:
create object B
call constructor B
call a,aa,aaa respectively
2.1 for a, call A(int x)
2.2 for aa, call A(int x)
2.3 for aaa, call A()
display B from B c-tor body
Now the 4. step is to call destructor B, I know that.
What I don't know is what is the order of calling destructors for A.
Is it a,aa,aaa respectively, or aaa,aa,a respectively?
Thanks in advance.
The member objects get destroyed in the reversed order they got constructed. Note that you do not influence this order by changing the order in the constructor's initialization list. The order is exclusively determined by the order you declare them in the struct/class definition.
What I don't know is what is the order of calling destructors for A. Is it a,aa,aaa respectively, or aaa,aa,a respectively?
Thus, the latter case is happening.
Everything looks fine. It constructs-destructs stack-wise (First in/Last out):
#include <iostream>
struct A
{
A() { name="untitled"; std::cout << name <<" constructor" << std::endl; }
A(std::string name):name(name) { std::cout << name <<" constructor" << std::endl; }
~A() { std::cout << name <<" destructor" << std::endl; }
std::string name;
};
struct B
{
A a, aa, aaa;
B() : aa("aa"), a("a") { std::cout << "B constructor" << std::endl; }
~B() { std::cout << "B destructor" << std::endl; }
};
B beta;
int main()
{
return 0;
}
Result:
a constructor
aa constructor
untitled constructor
B constructor
B destructor
untitled destructor
aa destructor
a destructor
Is this order guaranteed? yes
If you turn on all the warnings you see this:
g++ -Wall -Wreorder main.cpp
main.cpp: In constructor ‘B::B()’:
main.cpp:12:10: warning: ‘B::aa’ will be initialized after [-Wreorder]
A a, aa, aaa;
^
main.cpp:12:7: warning: ‘A B::a’ [-Wreorder]
A a, aa, aaa;
^
main.cpp:13:5: warning: when initialized here [-Wreorder]
B() : aa("aa"), a("a") { std::cout << "B constructor" << std::endl; }
^
This took forever to find, but per n4659 (ISO C++17 draft):
15.6.2 Initializing bases and members
paragraph (13.3)
Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).
[ Note: The declaration order is mandated to ensure that base and member subobjects are destroyed in the
reverse order of initialization. — end note ]
Here, mem-initializers are the list following the colon in the constructor definition.
This question already has an answer here:
Most vexing parse
(1 answer)
Closed 9 years ago.
class A {
public:
A() { cout << "A()" << endl; }
};
class B {
public:
A a;
B(const A& a1) : a(a1) { cout << "B(const A&)" << endl; }
/* B(const A& a1) { a = a1; cout << "B(const A&)" << endl; } */
};
int main() {
B b(A()); /* no ouput */
}
No output is generated for the above code. Is that due to the compiler optimization (copy elision) as discussed in this link?
But if I have a B class constructor and re-write the code like below:
class A {
public:
A() { cout << "A()" << endl; }
};
class B {
public:
A a;
B() {}
B(const A& a1) : a(a1) { cout << "B(const A&)" << endl; }
/* B(const A& a1) { a = a1; cout << "B(const A&)" << endl; } */
};
int main() {
B().a; // gives output A()
}
add an extra pair of parentheses:
B b((A()));
// you can also fix it using new C++11 initialization syntax:
B b{A()};
the problem you are facing it called most vexing parse, and it means compiler is not able to decide whether you want a function declaration or variable definition.
[edit]
I should also add that standard requires compiler in such case to choose function declaration.
[edit]
clang is actually more helpfull in this case, and gives hint to use partentheses:
http://rextester.com/PECQ53431
source_file.cpp:16:8: warning: parentheses were disambiguated as a function declaration [-Wvexing-parse]
B b(A()); /* no ouput */
^~~~~
source_file.cpp:16:9: note: add a pair of parentheses to declare a variable
B b(A()); /* no ouput */
^
( )
1 warning generated.
B b(A());
Is ambiguous and may be interpreted either as a variable declaration or as a declaration of a function that returns a restult of type B and takes a single unnamed parameter of type a function with no parameters and returns a result of type A. Although you may think first one should take place the standard dictates in fact the second one will happen. See the article about most vexing parse in wikipedia.
Instead of creating A object after B object creation, create first As object in main.
A a;
B b(a);
I'm using base-from-member idiom and I now stuck with copy/move constructors for them. Suppose following code:
#include <iostream>
#include <string>
#include <boost/lexical_cast.hpp>
using namespace std;
struct A // base class
{
A(string &s) : s(s), c(0) { };
A(const A &a) : s(a.s), c(a.c) { };
void print() { cout << s << endl; c++; }
int print_count() { return c; }
string &s;
int c;
};
struct B_base // this class will be initialized before A
{
B_base(int i)
{
s = boost::lexical_cast<string>(i);
}
B_base(const B_base &other) : s(other.s) { };
string s;
};
struct B : B_base, A // main class
{
B(int i) : B_base(i), A(B_base::s) { }
B(const B &other) : B_base(other), A(other) { } // <-- problem here
using A::print;
using A::print_count;
};
int main()
{
B b(10);
b.print(); // prints '10'
cout << b.print_count() << endl; // prints '1'
B b1(b);
b1.print(); // prints '10'
A &a = b;
a.s = "FAIL"; // we modify b, not b1 here!
b1.print(); // but b1 prints 'FAIL' here --- error (it should still print '10')
cout << b.print_count() << " " << b1.print_count() << endl; // prints '1 3'
return 0;
}
Problem here is that reference A.s (which is point to B_base::s) is copied from one instance to another, while it should be modified to point to another B_base::s. Things may be even worse, if previous instance is go out of scope ending with dangling references.
My question is: how can I make correct copy of class with base-from-member idiom? (I think move constructor will be similar to copy one, right?)
The base-from-member idiom you are exercising in this case means: you want a class B derived from A with have to be initialized using a member of B (with is: string s).
B b(10);
B b1(b); // B(const B &other) : B_base(other), A(other) { }
// now A::s in b1 is a ref to b.s
A &a = b;// and a.s is a ref to b.s too.
a.s = "FAIL"; // we modify b, and A::s in b1 to!
This problem can be solved making the copy constructor:
B(const B &other) : B_base(other), A(B_base::s) { }
Also, having A::s and B_base::s with the same name, make thing more difficult to understand.
EDIT: As a class designer, you have to decide with is the exact meaning of your copy constructor.
For example, in this case you may want to keep track (with A::c) of the number of printing of each newly create object A. The copy constructor I proposed do it.
But if you want to keep track of all printing of the original string thing are more complex. Just note that if you copy the old A::c to the new A it will be correct initialized, bur not cross actualized when the the printing of the same original string is made using different copies of A. If this is not a problem you can modify the constructors:
A(string &s, int _c=0) : s(s), c(_c) { };
...
B(const B &other) : B_base(other), A(B_base::s, other.c) { }
It seems the way to construct objects in C++0x avoiding copies/moves (particularly for large stack allocated objects) is "pass by lambda".
See the following code:
#include <iostream>
#define LAMBDA(x) [&] { return x; }
class A
{
public:
A() {};
A(const A&) { std::cout << "Copy "; }
A(A&&) { std::cout << "Move "; }
};
class B1
{
public:
B1(const A& a_) : a(a_) {}
B1(A&& a_) : a(std::move(a_)) {}
A a;
};
class B2
{
public:
B2(const A& a_) : a(a_) {}
B2(A&& a_) : a(std::move(a_)) {}
template <class LAMBDA_T>
B2(LAMBDA_T&& f, decltype(f())* dummy = 0) : a(f()) {}
A a;
};
int main()
{
A a;
std::cout << "B1 b11( a ): ";
B1 b11(a);
std::cout << std::endl;
std::cout << "B2 b12(LAMBDA(a)): ";
B2 b12(LAMBDA(a));
std::cout << std::endl;
std::cout << std::endl;
std::cout << "B1 b21( std::move(a) ): ";
B1 b21(std::move(a));
std::cout << std::endl;
std::cout << "B2 b22(LAMBDA(std::move(a))): ";
B2 b22(LAMBDA(std::move(a)));
std::cout << std::endl;
std::cout << std::endl;
std::cout << "B1 b31(( A() )): ";
B1 b31((A()));
std::cout << std::endl;
std::cout << "B2 b32((LAMBDA(A()))): ";
B2 b32((LAMBDA(A())));
std::cout << std::endl;
std::cout << std::endl;
}
Which outputs the following:
B1 b11( a ): Copy
B2 b12(LAMBDA(a)): Copy
B1 b21( std::move(a) ): Move
B2 b22(LAMBDA(std::move(a))): Move
B1 b31(( A() )): Move
B2 b32((LAMBDA(A()))):
Note the "pass by lambda" removes the move in the case where the parameter is a what I believe is called a "prvalue".
Note that it seems the "pass by lambda" approach only helps when the parameter is a "prvalue", but it doesn't seem to hurt in other cases.
Is there anyway to get functions to accept "pass by lambda" parameters in C++0x, that is nicer than the client having to wrap their parameters in lambda functions themselves? (other than defining a proxy macro that calls the function).
If you're okay with a templated constructor, you might as well use perfect forwarding instead of the obfuscation with lambdas.
class super_expensive_type {
public:
struct token_t {} static constexpr token = token_t {};
super_expensive_type(token_t);
}
constexpr super_expensive_type::token_t super_expensive_type::token;
class user {
public:
template<typename... Args>
explicit
user(Args&&... args)
: member { std::forward<Args>(args)... }
{}
private:
super_expensive_type member;
};
// ...
// only one construction here
user { super_expensive_type::token };
super_expensive_type moved_from = ...;
// one move
user { std::move(moved_from) };
super_expensive_type copied_from = ...;
// one copy
user { copied_from };
Using lambdas can't be better than this because the result from the expression in the lambda body has to be returned.
There's a fundamental problem with what you're doing. You cannot magic an object into existence. The variable must be:
Default constructed
Copy constructed
Move constructed
Constructed with a different constructor.
4 is off the table, since you only defined the first three. Your copy and move constructors both print things. Therefore, the only conclusion one can draw is that, if nothing is printed, the object is being default constructed. IE: filled with nothing.
In short, your Lambda-based transfer mechanism doesn't seem to be transferring anything at all.
After further analysis, I see what's happening. Your lambda isn't actually taking a value by reference; it's constructing a value. If you expand the macro, what you get is this:
B2 b32(([&] {return A()}));
It constructs a temporary; it doesn't actually take anything by reference. So I'm not sure how you can consider this "passing" anything. All you're doing is making a function that constructs an object. You could just as easily pass the arguments for B2::a's constructor to the constructor of B2 and have it use them to create the object, and it would give you the same effect.
You're not passing a value. You're making a function that will always create the exact same object. That's not very useful.