I am trying to understand the memory used in a particular type of initialization. Here is an example for the question:
#include <iostream>
using namespace std;
class Example {
int n;
public:
Example(int number = 0)
{
n = number;
}
};
int main() {
Example *obj1 = new Example(1); //dynamic allocation - 1 instance is created and the object pointer points to the address
Example obj2(2); // automatic allocation - a single instance of the object is created with the given value
Example obj3 = Example(3); //automatic allocation - with copy constructor from an object initialized with a the class constructor
delete obj1; //de-allocating dynamically allocate memory
}
I am interested in knowing how obj3 is being instantiated. Does the usage of the equal to sign mean that we are using a copy constructor here? If so, is Example(3) a separate instance (what is its scope)?
If they are separate instances, then it seems the initialization of obj2 more optimized, isn't it?
Edit: Fixed usage of incorrect terminology - static to automatic
I am interest in knowing how obj3 is being instantiated. Does the usage of the equals to sign mean that we are using a copy constructor here? If so, is Example(3) a separate instance (what is its scope)?
This expression is known as copy initialization and your case with obj3 dsescribed here:
First, if T is a class type and the initializer is a prvalue expression whose cv-unqualified type is the same class as T, the initializer expression itself, rather than a temporary materialized from it, is used to initialize the destination object: see copy elision (since C++17)
So no copy ctor involved and obj3 is initialized directly (passing 3 to its ctor) for the current standard. Before C++17 temporary could be created but most probably it would be eliminated by optimizer.
Note: you incorrectly stated in comment for automatic variables to use static memory allocation. Please see details here Difference between static memory allocation and dynamic memory allocation
Related
Let's consider that during the execution of the constructor of a class S, it appears that S could be constructed using another constructor. One solution could be to make a placement new at this to reuse the storage:
struct S{
unsigned int j; //no const neither reference non static members
S(unsigned int i){/*...*/}
S(int i){
if (i>=0) {
new (this) S(static_cast<unsigned int>(i));
return;}
/*...*/
}
};
int i=10;
S x{i};//is it UB?
Storage reuse is defined in [basic.life]. I don't know how to read this section when the storage is (re)used during constructor execution.
The standard is completely underspecified in this case, and I cannot find a relevant CWG issue.
In itself, your placement new is not UB. After all, you have storage without an object, so you can directly construct an object in it. As you correctly said, the lifetime of the first object hasn't started yet.
But now the problem is: What happens to the original object? Because normally, a constructor is only called on storage without an object and the end of constructor marks the start of the lifetime of the object. But now there is already another object. Is the new object destroyed? Does it have no effect?
The standard is missing a paragraph in [class.cdtor] that says what should happen if a new object is created in the storage of an object under construction and destruction.
You can even construct even weirder code:
struct X {
X *object;
int var;
X() : object(new (this) X(4)), var(5) {} // ?!?
X(int x) : var(x) {}
} x;
is it UB?
No it is not. [basic.life]/5 says:
A program may end the lifetime of any object by reusing the storage which the object occupies or by explicitly calling the destructor for an object of a class type with a non-trivial destructor. For an object of a class type with a non-trivial destructor, the program is not required to call the destructor explicitly before the storage which the object occupies is reused or released; however, if there is no explicit call to the destructor or if a delete-expression is not used to release the storage, the destructor shall not be implicitly called and any program that depends on the side effects produced by the destructor has undefined behavior.
Emphasis on the part relevant to your class which has a trivial destructor. About the specific new (this) T; form, I found no exception to this rule in [class.cdtor] nor [class.dtor].
The boost::aligned_storage data type is useful to me in order to provide aligned storage in a pre-c++11 world. I have a class that contains this storage member:
template <size_t StoreSize>
class RoutineStorage {
enum { ROUTINE_STORAGE_SIZE = StoreSize};
enum { BUFFER_ALIGNMENT_VALUE = 8 };
template <typename TStorageType> TStorageType& getStorageAsType()
{
BOOST_STATIC_ASSERT_MSG(boost::has_trivial_assign<TStorageType>::value &&
boost::has_trivial_copy<TStorageType>::value,
"The storage type must be trvially copyable and assignable to support this classes "
"copy|assign semantics.");
... // Checking and some other code.
return new (_store.address()) TStorageType();
}
private:
typedef boost::aligned_storage<ROUTINE_STORAGE_SIZE, BUFFER_ALIGNMENT_VALUE>
StorageBuffer;
StorageBuffer _store;
}
I would like to provide a copy constructor for this class, but when i look at the implementation of aligned_storage it has a copy constructor listed as private and a comment // noncopyable. There doesn't seem to be an explanation for this in any of the boost pages about this type, so i concluded that they didn't want to handle copying of different possible templated buffer sizes. I suspect that the following will be fine for copying this buffer:
RoutineStorage(const RoutineStorage<StoreSize>& copy)
{
std::memcpy(_store.address(), copy._store.address(), _store.size())
}
Will there be a problem with this? As far as i can tell the aligned_buffer address function will give the start of a continues memory address and size will let me always copy the correct size.
Just copying the buffer like you do in
RoutineStorage(const RoutineStorage<StoreSize>& copy)
{
std::memcpy(_store.address(), copy._store.address(), _store.size())
}
is not enough. Yes, you will have an exact copy, but you don't actually have the object you created in that StorageBuffer. [intro.object]\1 states that
The constructs in a C++ program create, destroy, refer to, access, and manipulate objects. An object is created by a definition ([basic.def]), by a new-expression, when implicitly changing the active member of a union ([class.union]), or when a temporary object is created ([conv.rval], [class.temporary]).
so until you copy the object into store with placement new you don't actually have an object, just storage.
Lets say you are storing a Foo. Originally you would create the Foo in the StorageBuffer like
Foo* f = new(_store.address()) Foo();
So, in the copy constructor you just need to call the copy constructor of Foo and placing that into _store like
RoutineStorage(const RoutineStorage<StoreSize>& copy)
{
f = new(_store.address()) Foo(copy.*f);
}
#include <iostream>
using namespace std;
class A {
public:
A() {
cout << "Default Ctor" << endl;
}
};
int main() {
A(); // <------- Problem
return 0;
}
It shows Default Ctor on console. My questions
Is is valid?
If so, how did it instantiate since I didn't use new or any object?
You are creating a new object with A().
Is is valid?
Yes it is.
If so, how did it instantiate since I didn't use new or any object?
new simply creates the object in dynamic memory. You're creating the object in automatic memory. Also, just because you didn't give the object a name, doesn't mean it isn't created.
Think of this:
int foo() { return 1; }
int main()
{
foo();
}
Leaving optimizations aside Did foo() actually return 1? Yes it did. Just that you're not using it.
EDIT:
Let's break it down a bit:
A(); //creates a temporary unnamed object in automatic storage
A a; //creates an object a of type A in automatic storage
A a(); //creates no object, but declare a function a returning A and taking no parameters
A a(A()); //these two are equivalent
A a = A(); //creates a temporary unnamed object and creates an object a in automatic storage
//using the compiler-generated copy constructor
A a;
a = A(); //creates an object a in automatic storage
//creates an unnamed temporary object and uses the compiler-generated assignment operator
//to assign it to a
A a = &A(); //invalid, &A() is the address of a temporary a, which is illegal
Is is valid?
Yes, It is valid
What exactly happens?
A();
Creates a temporary nameless object of the type A by calling its default no argument constructor but the object is destructed by the time the next statement is executed since.
If so, how did it instantiate since I didn't use new or any object?
You can create objects on the local/automatic storage or on dynamic storage depending on your usage.
When you use new objects are created on dynamic storage(heap), when you create a object as you have it is created on the local/automatic storage(stack).
So using new only determines where the object will be created not whether it will be created.
What are Temporary Nameless objects?
You do not always need to name an object to instantiate them.
For Ex:
While calling function, when you pass objects by value temporary nameless objects are created and automatically destroyed all the time.These are objects which do not have any name and hence cannot be explicitly referred through program but they do serve the purpose for which they were created.
In simple words,
You are creating a nameless temporary object on the local/automatic storage which does not exist once the statement completes execution.
C++ says that we can't return anything from the constructor? What is the historical reason behind it?
Why did Bjarne disallow contructors to return something unlike any other member function?
Because when an object is being constructed in a new statement or in a variable initializer, the object that is returned is that new object which is being constructed. What would you ever do with an object returned from a constructor? It couldn't ever be returned anywhere; it's the object being constructed that is returned. That object has already been (partially) created before the constructor is called (otherwise, the constructor wouldn't have an object to work on), and it must be what is returned from the constructor, so there is no point in making the user return it or allow them to confuse themselves by trying to return something different.
I think of a constructor as returning itself, but without having to have a return statement.
If it returns itself, then it cannot return anything else.
I can't speak for Bjarne, but the idiomatic way to look at a constructor is that it is returning the object it constructed.
Aside from the fact that having the constructor return something would give constructors two things to do instead of just one (which is generally an undesirable thing), note that constructors can't be named so it is impossible to call them explicitly.
As it's impossible to construct an expression that is an explicit call to a constructor, it would be impossible to assign or refer to a constructor's return value in any case.
Attempting to return something from a constructor just doesn't fit with the language design at all.
Constructors don't "return" objects, they initialize objects in the memory area in which they are invoked. If you declare an object of class type with static storage duration (and that type has a user-declared constructor), the memory is reserved for the lifetime of the program and the implementation ensures that the constructor is called to initialize the object at that location at the appropriate time in the program.
Similarly, if you declare and object with automatic storage duration, the implementation reserves space (informally some stack space) and invokes the constructor each time the declaration statement is executed.
In the case of a new expression, the memory is allocated dynamically and the implementation calls the appropriate constructor to initialize the object.
Note that if X is a class type, the X in all of these statements always refers to the name of the type and never the constructor which doesn't actually have a name. The syntax for declaring or defining a constructor is special, it doesn't mean that the constructor has a name. Assume that X has a user-declared constructor.
X x; // Initialize an object of type X using the default constructor
X(); // Value initialize a temporary of type X. Not an explicit constructor call.
new X(); // new expression: value-initialize a dynamically allocated X
X(a); // A function style cast
X(a, b); // Construct an X from the expression list. X must have a
// suitable constructor but the X still refers to the type.
The constructor can only yield the object itself...
Constructor don't have retunrn type bacause it already returns the refrence_id to refrence variable(which is called as an object) for ex:-
Emp e1 = new Emp(refrence_id)
here Emp is the class_name
e1 is the refrence variable
new is used for dynamic allocation
Emp() is the constructor of class Emp
in this constructor returns the refrence_id to refrence variable e1
in C++, what is the exact difference between both following dynamic object creations :
A* pA = new A;
A* pA = new A();
I did some tests, but it seems that in both cases, the default constructor is called and only it. I'm looking for any difference about performance...
Thanks
If A is a POD-type, then new A will allocate a new A object but leave it with an indeterminate value, otherwise new A will default initialize the new object.
In all cases new A() will value initialize the new A object.
This is obviously different behaviour for POD types but also affects non-POD, non-union class types without a used-declared constructor.
E.g.
struct A
{
int a;
std::string s;
};
A is a non-POD class type without a user-declared constructor. When an A is default initialized the implicitly defined constructor is called which calls the default constructor for s (a non-POD type), but a is not initialized.
When an A is value initialized, as it has no used-declared constructor, all of its members are value initialized which means that the default constructor for s is called and a is zero initialized.
ISO 14882:2003 references:
5.3.4 [expr.new]/15: How objects allocated by a new expression are initialized depending on whether the initializer is omitted, a pair of parentheses or otherwise.
8.5 [dcl.init]/5: The meaning of zero initialize, default initialize and value initialize.
12.1 [class.ctor]/7,8: The form of a user-written constructor that matches the behaviour of an implicitly defined default constructor.
12.6.2 [class.base.init]/4: How bases and members which are not listed in a member initializer list of a constructor are initialized.
It's exactly the same, also performance wise :)
The lexer will have to scan two characters less in the first version, so the compilation process is a little faster ;)
please see STL implementing code (e.g. allocator) then you'll understand.