Suppose I have a class
class A {
public:
A(int i);
~A();
private:
B b; // Want <- this guy to be constructed with i in A's constructor!
};
I want b to be constructed in the constructor with particular parameters that aren't known until A is constructed. If I were to do the following in A's constructor:
A::A(int i) {
B b(i);
// Or even if I try to do b = B::B(i);
}
I notice that b get's allocated twice on the stack! aghghg.
Then I found out that what I can do in A's constructor is:
A::A() : b(B::B(7)) {
}
And b only gets allocated on the stack once!
But this is pretty clunky. Anyone got a better idea? Remember, the constructor should only be called once!
Is this the standard way of allocating objects NON-dynamically with important parameters? What if we can shove b's construction into that fancy argument list thing!? You're forced to either dynamically allocate, or construct TWICE on the stack!
Bonus Question: When does b get deallocated? Is it after or right before A's destructor
I'm sorry to say but you have it all wrong.
What you need to do is to pick up a good beginner's C++ book. This is such a fundamental part of the language that if you don't understand this you will struggle when dealing with non-trivial C++ code.
That being said, when an object is about to be created, all subobjects will be created first. If you need to pass parameters to those subobject constructors, you need to create what's called an initializer list:
A::A(int i) : b(i) {}
The stuff that follows the colon and before the first brace is the initializer list. Only constructors can have them. What's going on here is that we pass the value of i to the b subobject's constructor. This happens before the constructor for A is called!
So for your case, the order of construction is:
The b subobject
The A object itself
The order of destruction is the complete opposite process.
does
A::A() : b(7) { }
not work?
Edit: I'm at work, so I'll do a more comprehensive edit later using some profile stuff to see what gcc does w.r.t. deallocation. I suspect that nobar is right and all deallocation happens at once.
b(B::B(7)) works as well as b(7) because B::B(7) creates a temporary B variable. b is then copy-constructed from that temporary. A decent optimizing compiler should be able to reduce the second case to the first but:
b(7) is more idiomatic -- other c++ programmers will recognize is more easily
You really don't know for sure what a compiler will do.
if B is not copy-constructible, or expensive to copy-construct, you may not want to deal with the added overhead if, like most, you turn off optimizations for debugging.
It only takes a small modification to your program to demonstrate the order of construction and destruction.
#include <iostream>
using std::cerr;
class B
{
public:
B( int ) { cerr<<"B()\n"; ;}
~B() { cerr<<"~B()\n"; }
};
class A
{
B b;
public:
A( int i ) : b(i) { cerr<<"A()\n"; }
~A() { cerr<<"~A()\n"; }
};
int main()
{
A a(7);
}
Here's the output:
$ make destructor_order && ./destructor_order
B()
A()
~A()
~B()
Related
I have a vector of class instances. Each of those instances has a unique_ptr to another class.
Since I never try to copy the class instance or even share the pointer, I felt like unique_ptr are more appropriate than shared_ptrs since the pointer is not shared, but only accessible through the class instance.
Is it bad practice? And why wouldn't this work? I understand that copying an instance to a unique pointer would be ill-formed, but since I move it, I do not understand why this would not be allowed?
Would I have to create a custom move constructor? And what should it do?
The unique ptr should be deleted as soon as the object instance is being removed from the vector as there are no references left, right?
Code Example for better understanding:
class A {
private:
int number;
public:
void f() {
std::cout << "The number is: " << number;
}
A(int i) : number{i} {}
~A() = default;
};
class B {
std::unique_ptr<A> good_a;
B() : good_a{ std::make_unique<A>(1) } {}
~B() = default;
};
int main()
{
std::vector<B> all;
B my_b(123);
all.emplace_back(std::move(my_b));
}
This answer focuses on compilation error you seem to be having. Bad or good practice is left for others to chime in.
Your code have several errors there, but the main one seems to be that your custom B( ) constructor inhibits default move constructor. If you add it, your code becomes well-formed.
Here is a full working code for the reference:
#include <memory>
#include <vector>
class A {
private:
int number;
public:
void f();
A(int i) : number{i} {}
~A() = default;
};
struct B {
std::unique_ptr<A> good_a;
B(int k) : good_a{ std::make_unique<A>(k) } {}
B(B&& ) = default;
B& operator=(B&& ) = default; // not needed for the example, but good for completeness
};
int main()
{
std::vector<B> all;
B my_b(123);
all.emplace_back(std::move(my_b));
}
And why wouldn't this work?
What you described could work.
I do not understand why this would not be allowed?
What you described would be allowed.
Would I have to create a custom move constructor?
No, that wouldn't be necessary, unless you define other special member functions, or have other members (beside the unique pointer) that have deleted or private move constructor.
The unique ptr should be deleted as soon as the object instance is being removed from the vector as there are no references left, right?
Members are destroyed when the super object is destroyed. And the destructor of the unique pointer invokes the deleter on its owned pointer.
Whether there are references to the pointed object has no effect on whether it is deleted or not. Anything referring to the deleted object will be left dangling.
Is it bad practice?
There isn't necessarily anything particularly bad about what you described in general, but that depends on exact details.
One potential issue is that dynamic allocation can be expensive in some cases, and using it unnecessarily would then be unnecessarily expensive. As such, you should to have some reason to allocate the pointed objects dynamically rather than storing them directly as members.
Bugs in your example:
You attempt to initialise B(123) but B has no constructor accepting an integer.
You attempt to initialise a B outside a member function of B, but its constructors and the destructor have private access.
You have user declared destructor for B, but no user declared move constructor or assignment operators and therefore the class isn't movable, which is a requirement for storing in std::vector.
Here is a fixed version that doesn't use unnecessary dynamic allocation:
struct A {
int number;
};
struct B {
A good_a;
};
B my_b{123};
all.push_back(my_b);
Please read this answear.
Depending what is explicitly declared respective constructors with default implementation are implicitly defined or dropped. Rules are described by this table:
Since you have used explicit defined destructor (as default) you have disabled ("not declared") move constructor.
So to fix it you have to explicitly define move constructor or remove definition of destructor: https://godbolt.org/z/dr8KrsTfq
I want to initialize member object variables in the default constructor of the class.
Let's consider the following,
class ABC {
ABC(int A, int B) {
a = A;
b = B;
}
int a;
int b;
};
class Foo {
Foo();
ABC m_obj1;
};
From the above example, I would like to initialize "obj1" in "Foo::Foo()".
One of the restrictions I have is that I cannot do so in the initializer list, as I need to do some computation before I could initialize the member. So the option available (ASFAIK) is to do so in the body of the default constructor only.
Any inputs, how could I do this?
Edit: Restricting to C++11
Would this be a correct way,
Foo:Foo() {
int x = 10;
int y = 100;
m_Obj1(x, y); //Is this correct? <--------
}
Depending on your exact problem and requirements, multiple solutions might be available:
Option 1: Use a function to do the computations and call Foo constructor
Foo makeFoo()
{
// Computations here that initialize A and B for obj1 constructor
return Foo(A, B)
}
Option 2: Call a function that does the computations and initialize obj1 in Foo member initializer list
ABC initABC() {
// Some computations
return ABC(A, B)
}
Foo() : obj1(initABC()) {}
Option 3: Dynamically allocate obj1, for instance with a std::unique_ptr
Option 4: Use std::optional or an emulated c++11 version as shown by other answers
You simply call the base constructor inside the initializer list of the derived constructor. The initializer list starts with ":" after the parameters of the constructor. See example code!
There is no problem to call functions inside the initializer list itself.
int CallFunc1(int x) { return x*2; }
int CallFunc2(int y) { return y*4; }
class ABC {
public:
ABC(int A, int B):a{CallFunc1(A)},b{CallFunc2(B)} {
std::cout << "Constructor with " << a << " " << b << " called" << std::endl;
}
private:
int a;
int b;
};
class Foo {
public:
Foo(): obj1(1,2){}
Foo( int a, int b): obj1(a, b){}
private:
ABC obj1;
};
int main()
{
Foo foo;
Foo fooo( 9,10);
}
edit:
The best method I can think of for your case is a copy constructor, being more specific on what you need to store helps a lot since if it is just two ints inside a class dynamic allocation is not worth it, the size of the object being constructed makes a difference to what method is best, copy constructors can be slower with much larger data types as the object has to be created twice: once when it is automatically constructed in the parent objects constructor and again when a temporary object is created and all the values have to be copied, which can be slower then dynamically allocating if the size is larger.
As far as I'm aware all objects in a class are automatically initialized/allocated in the constructor so sadly dynamic memory use may be your best bet here.
If you are fine with having the object initialized but empty so you know it is not 'ready' yet you can later fill it with useful data when you would have wanted to initialize it. This can be done with default constructors that set the things inside the object to null values or something similar so you know the object hasn't been properly initialized yet. Then before using the object you can check whether it has been initialized by checking for the null values or by having put a bool in the object that tells you whether it is initialized. Dynamically allocated would still be better in my opinion and makes the code look cleaner overall as all you need to store is a null pointer until the object is needed and then allocated and set to the pointer. It is also very easy to check if the pointer is equal to nullptr to know the state of your object.
Dynamically allocating memory may be a hassle since you have to make sure to get rid of memory leaks and it is slightly slower than using the stack, but it is a necessary skill for c++ since the stack is not enough when making programs that use more than the few available megabytes of data on the stack so if you are doing this simply to avoid the hassle I recommend learning it properly. It would be nice if you could be more specific about what kind of object you want to do this with or if you just want an answer that works for most cases.
eg:
*ABC obj1 = nullptr;
...object is needed
obj1 = new(ABC(constructor stuff));
...obj1 isn't needed
delete obj1;
or c++ automatically deletes it when the program closes.
I have the following code snippet:
#include <iostream>
using namespace std;
class A {
int* data;
int size;
public:
A(int s):size(s)
{
data = new int[size];
}
A() {
data = nullptr;
}
~A() {
if (data) delete [] data;
}
};
class B {
A a[2];
public:
B() {
a[0] = A(10);
a[1] = A(11);
}
};
int main(int argc, char *argv[]) {
B b;
}
In the C++ code above, I have class A which has an array member int* data, and the (de)allocation of memory are handled by (de)constructor. The I created class B which has an array of class A of fixed length as a data member.
My question is: how to elegantly initialise the member A a[2]? In the code above, the A(10) and A(11) are created on the stack, when jumping out of the scope, their destructors will be called, hence the data comes invalid. When jumping of the main function's scope, the pointers held by a[2] will be deallocated twice, causing the error:
pointer being freed was not allocated.
One possible solution is to carefully design a copy constructor and a move constructor, by doing so the above coding paradigm could work.
Another solution I've tried is to initialise the array in the initialization list of class B:
B() : a { A(10), A(11) }
This solution works and I don't really tell the underlying mechanism of initialization list. I think it must be quite different from simply construct and copy. I really expected some experts could give an elaborate explanation of this mechanism. Of course, this solution is ugly hard-coded and not flexible.
So I wonder if there are some programming paradigms in C++ to tackle this design problem?
In the code above, the A(10) and A(11) are created on the stack
They are temporary objects. It is not specified where they are created or if they're created at all.
when jumping out of the scope, their destructors will be called
The destructor of each temporary will be called after the corresponding move assignment statement ends.
One possible solution is to carefully design a copy constructor and a move constructor, by doing so the above coding paradigm could work.
And {copy,move} assignment operator too. You should always do that when the implicitly declared ones don't do the right thing. And they never do the right thing if you delete something in the destructor.
Another solution I've tried is to initialise the array in the initialization list of class B
This solution works and I don't really tell the underlying mechanism of initialization list. I think it must be quite different from simply construct and copy.
The bug in the original code is badly behaving move assignment operator of A. Since the initialization list never move assigns from a temporary, it never triggers the bug.
This is actually the more elegant way to construct a that you asked for. Not because it avoids the bug, but because avoiding unnecessary moving is good thing, intrinsically.
So I wonder if there are some programming paradigms in C++ to tackle this design problem?
Yes. RAII and Single responsibility principle. Unless your class does nothing else, besides managing the memory pointed by data, it should not be managing the memory. Instead, it should delegate the memory management to a RAII object. In this case, you should use a std::vector member.
class A {
std::vector<int> data;
public:
A(int s):data(s) {}
A() = default;
};
Using an initializer list to construct B::a, like this:
class B {
A a[2];
public:
B() : a({10, 11}){
}
};
The ideal answer would be to force A to use movements instead of copies, or on a copy to allocate new space for the item. Of the two, the most efficient is the former and so I will expand on it below:
Forcing movement can be done in two fashions:
Delete the copy constructor and copy operator=, and implement your own move constructor and operator=
Consistently use std::move and std::swap.
Of these, the former is superior in that you will be unable to accidentally copy the class, but with the latter the fact that you are moving will be more evident.
To delete the default copy methods do:
class A {
A( const A& a ) = delete;
A& operator =( const A& a ) = delete;
}
I was under impression that it's impossible, see for example:
Calling the constructor of the base class after some other instructions in C++
But the following program runs and produces two lines of "Constructor Person":
#include <iostream>
class Person
{
public:
Person()
{
std::cout << "Constructor Person" << std::endl; }
};
class Child : public Person
{
public:
Child()
{
c = 1;
Person();
}
int c;
};
int main()
{
Child child;
return 0;
}
The first one is implicit call of the default constructor, that's clear. What about the 2nd one - does it mean that the action described in the title is legitimate? I use Visual C++ 2010.
The call inside the child class constructor is not calling the base class constructor, it is creating a temporary, unnamed and new object of type Person. It will be destroyed as the constructor exits. To clarify, your example is the same as doing this:
Child() { c = 1; Person tempPerson; }
Except in this case, the temporary object has a name.
You can see what I mean if you modify your example a little:
class Person
{
public:
Person(int id):id(id) { std::cout << "Constructor Person " << id << std::endl; }
~Person(){ std::cout << "Destroying Person " << id << std::endl; }
int id;
};
class Child : public Person
{
public:
Child():Person(1) { c = 1; Person(2); }
int c;
};
int main() {
Child child;
Person(3);
return 0;
}
This produces the output:
Constructor Person 1
Constructor Person 2
Destroying Person 2
Constructor Person 3
Destroying Person 3
Destroying Person 1
The following is an excerpt from "Accelerated C++":
"Derived objects are constructed by:
1. Allocating space for the entire object (base class members as well as derived class members);
2. Calling the base-class constructor to initialize the base-class part of the object;
3. Initializing the members of the derived class as directed by the constructor initializer;
4. Executing the body of the derived-class constructor, if any."
Summarizing the answers and comments: Calling a constructor of the base class from a subclass' constructor body is impossible in the sense that #2 above must precede #4.
But we still can create a base object in the derived constructor body thus calling a base constructor. It will be an object different from the object being constructed with the currently executed derived constructor.
You can't call it from the body of the child constructor, but you can put it into the initializer list:
public:
Child() : Person() { c = 1; }
Of course it's not helpful to call the default constructor of the parent because that will happen automatically. It's more useful if you need to pass a parameter to the constructor.
The reason you can't call the constructor from the body is because C++ guarantees the parent will be finished constructing before the child constructor starts.
The answers to this question while usually technically true and useful, don't give the big picture. And the big picture is somewhat different than it may seem :)
The base class's constructor is always invoked, otherwise in the body of the derived class's constructor you'd have a partially constructed and thus unusable object. You have the option of providing arguments to the base class constructor. This doesn't "invoke" it: it gets invoked no matter what, you can just pass some extra arguments to it:
// Correct but useless the BaseClass constructor is invoked anyway
DerivedClass::DerivedClass() : BaseClass() { ... }
// A way of giving arguments to the BaseClass constructor
DerivedClass::DerivedClass() : BaseClass(42) { ... }
The C++ syntax to explicitly invoke a constructor has a weird name and lives up to this name, because it's something that's very rarely done - usually only in library/foundation code. It's called placement new, and no, it has nothing to do with memory allocation - this is the weird syntax to invoke constructors explicitly in C++:
// This code will compile but has undefined behavior
// Do NOT do this
// This is not a valid C++ program even though the compiler accepts it!
DerivedClass::DerivedClass() { new (this) BaseClass(); /* WRONG */ }
DerivedClass::DerivedClass() { new (this) BaseClass(42); /* WRONG */ }
// The above is how constructor calls are actually written in C++.
So, in your question, this is what you meant to ask about, but didn't know :) I imagine that this weird syntax is helpful since if it were easy, then people coming from languages where such constructor calls are commonplace (e.g. Pascal/Delphi) could write lots of seemingly working code that would be totally broken in all sorts of ways. Undefined behavior is not a guarantee of a crash, that's the problem. Superficial/obvious UB often results in crashes (like null pointer access), but a whole lot of UB is a silent killer. So making it harder to write incorrect code by making some syntax obscure is a desirable trait in a language.
The "second option" in the question has nothing to do with constructor "calls". The C++ syntax of creating a default-constructed instance of a value of BaseClass object is:
// Constructs a temporary instance of the object, and promptly
// destructs it. It's useless.
BaseClass();
// Here's how the compiler can interpret the above code. You can write either
// one and it has identical effects. Notice how the scope of the value ends
// and you have no access to it.
{
BaseClass __temporary{};
}
In C++ the notion of a construction of an object instance is all-permeating: you do it all the time, since the language semantics equate the existence of an object with that object having been constructed. So you can also write:
// Constructs a temporary integer, and promptly destructs it.
int();
Objects of integer type are also constructed and destructed - but the constructor and destructor are trivial and thus there's no overhead.
Note that construction and destruction of an object this way doesn't imply any heap allocations. If the compiler decides that an instance has to be actually materialized (e.g. due to observable side effects of construction or destruction), the instance is a temporary object, just like the temporaries created during expression evaluation - a-ha, we notice that type() is an expression!
So, in your case, that Person(); statement was a no-op. In code compiled in release mode, no machine instructions are generated for it, because there's no way to observe the effects of this statement (in the case of the particular Person class), and thus if no one is there to hear the tree fall, then the tree doesn't need to exist in the first place. That's how C++ compilers optimize stuff: they do lot of work to prove (formally, in a mathematical sense) whether the effects of any piece of code may be unobservable, and if so the code is treated as dead code and removed.
Yeah, I know this is a year old but I found a way to do it. This may not be the best practice. For example, destroying the base class instance from within the derived class constructor sounds like a recipe for disaster. You could skip the destructor step, but that may lead to a memory leak if the base class constructor does any allocation.
class Derived : public Base
{
public:
Derived()
{
// By the time we arrive here, the base class is instantiated plus
// enough memory has been allocated for the additional derived class stuff.
// You can initialize derived class stuff here
this->Base::~Base(); // destroy the base class
new (this) Base(); // overwrites the base class storage with a new instance
}
};
I have a question about this:
class A
{
int a;
int* pa;
public:
A(int i):a(i) , pa(new int(a))
{
cout<<"A ctor"<<a<<endl;
}
~A()
{
delete pa;
cout<<"dtor\n";
}
int * &get()
{
return pa;
}
};
class B : public A
{
int b;
public:
B (A obj): A(obj) , b(0)
{
cout<<"B ctor\n";
}
~B()
{
cout<<"B dtor\n";
}
};
int main()
{
int i = 23 ;
A* p = new B(i);
}
Can tell me why the last line in main compiles? I pass an int into B's constructor which expects an A object instead. I believe that the int is translated to an A in B's constructor, but why?
Thanks in advance.
Avri.
Since you have not declared A constructor as explicit compiler is creating an anomymous instance of A using i and using it to initialize B instance. If you don't want the compiler to do these implicit conversions declare your costructor as explicit. Then you will get a compiler error.
Because A has a single parameter constructor which takes an int and isn't marked explicit you can implicitly convert an int to an A.
When you do new B(i), because the only viable constructor for B takes an A, an attempt is made to convert i to an A and construct the new B from that. This conversion is done by creating a temporary A using the constructor that takes an int.
When the B object is constructed, the base class A is copy constructed from the temporary A which means copying the member variables a and pa from the temporary A.
Strictly, because the constructor takes an A object by value, the temporary is, conceptually, copied again. The compiler may, however, eliminate the temporary by constructing the constructor parameter for B directly from i so the effect may well look like just a single copy.
This will cause a serious error because when the temporary A is destroyed, delete pa will cause the dynamically allocated int to be destroyed but the base class A of the newly allocated B object will still have a copy of this pointer which now no longer points at an invalid object. If the compiler doesn't eliminate one of the copies, a "double free" will happen immediately.
The key aspect of A is that it has a user-defined destructor that performs a resource action (deallocation). This is a strong warning that A needs a user-defined copy constructor and copy assignment operator because compiler generated version are likely not to work consistently with the design of A.
This is known as the "rule of three" which says that if you need a user-defined version of one of the destructor, copy constructor or copy assignment operator then you are likely to need user-defined versions of all of them.
Were you to attempt to free the dynamically allocated B object in your example, it would likely cause a "double free" error. In addition, A's destructor would need to be marked as virtual for a delete through a pointer to A to work correctly.
Since there is a conversion from int to A, implicitly your code is translated into
A* p = new B(A(i));