STL vector allocations - c++

I was wondering why the vector templates perform two allocations, when only one seems to be
necessary.
For example this:
#include <vector>
#include <iostream>
class A {
public:
A(const A &a) {
std::cout << "Calling copy constructor " << this << " " << &a << "\n";
}
A() {
std::cout << "Calling default constructor " << this << "\n";
}
~A() {
std::cout << "Calling destructor " << this << "\n";
}
};
int main(int argc, char **argv)
{
std::vector <A> Avec;
std::cout << "resize start\n";
Avec.resize(1);
std::cout << "resize end\n";
return 0;
}
Outputs:
resize start
Calling default constructor 0x7fff9a34191f
Calling copy constructor 0x1569010 0x7fff9a34191f
Calling destructor 0x7fff9a34191f
resize end

It isn't performing two allocations, it is creating an object by the default constructor to pass into resize, then copying that object into the new position, then destructing the argument.
If you look at the arguments to resize:
void resize(n, t = T())
It has as a defaulted argument a default constructed object of type T (this is the default constructor being called in your output). Then, within the function, it copies this into the correct position (this is the copy constructor). After the resize function ends, destroys the argument (the destructor call in the output).

Here is a guess:
The compiler re-ordered the initial allocation of Avec until after the "resize start"
The vector is initially allocated with 0 elements
The resize gets the new element filled with a default A (which was achieved by createing a default A, copying it into the vector, and deleting the temporary.

If you initialize objects that way the vector template creates objects by making a copy.
If you don't want to call copy constructor you should make :
vector<A*> Avec;
avec.push_back(new A());
http://www.cplusplus.com/reference/stl/vector/vector/

Related

Why std::move doesn't avoid a second destruction?

I know ordinary std::vector::push_back() will copy the object. I hope this code would only destruct a only once, using std::move() and A(A&&) noexcept to avoid copying. But it doesn't seem to work.
Is there any way that I can construct an object before push_back() and move it into a vector perfectly?
#include <bits/stdc++.h>
using namespace std;
class A {
public:
A() { std::cout << "construct" << this << '\n'; }
A(A&&) noexcept { std::cout << "move" << this << "\n"; }
A(const A&) = delete;
~A() { std::cout << "destruct" << this << '\n'; }
};
std::vector<A> as;
void add(A&& a) {
std::cout << "add 1\n";
as.push_back(std::move(a));
std::cout << "add 2\n";
}
int main() {
add(A());
std::cout << "main2\n";
return 0;
}
Output:
construct0x16d20b1fb
add 1
move0x151e068b0
add 2
destruct0x16d20b1fb
main2
destruct0x151e068b0
I hope this code would only destruct a only once, using std::move() and A(A&&) noexcept to avoid copying.
Using Move constructor perverts copying but doesn't prevent creating new objects, you are creating an inline object with default constructor "cout : construct0x16d20b1fb" and then from that object's data your going to create a 'NEW' object and calling move constructor will
transform the ownership of the object's data/resources to the new object that is being 'Constructed' so that explain the "cout : move0x151e068b0" then the line is finished so your inline object is destroyed "cout " destruct0x16d20b1fb" then your program finishes "cout : destruct0x151e068b0" your object that made via move constructor is destroyed.
you are expecting the behavior of pointers from your vector of "Objects" which is supposed to hold actual objects not pointer to other objects so it needs to containt objects and each of objects that are in that vector has a different address, unless you create your object and use a vector pointers to objects.
By the way std::move is but a cast, it casts to rvalue references so when you are capturing with rvalue reference there's no need to cast it again, you should be using it like this:
A a_object1;
vector.push_back(std::move(a_object1));
and it will use the move constructor. although in this case it will cast it implicitly because you are capturing only by rvalue reference in add function unless you add an overload to this function that also takes reference there's no need.

Why is the copy constructor called in this example with std::vector?

#include <iostream>
#include <vector>
using namespace std;
// Move Class
class Move {
private:
// Declare the raw pointer as
// the data member of class
int* data;
public:
// Constructor
Move(int d)
{
// Declare object in the heap
data = new int;
*data = d;
cout << "Constructor is called for "
<< d << endl;
};
// Copy Constructor
Move(const Move& source)
: Move{ *source.data }
{
cout << "Copy Constructor is called -"
<< "Deep copy for "
<< *source.data
<< endl;
}
// Move Constructor
Move(Move&& source)
: data{ source.data }
{
cout << "Move Constructor for "
<< *source.data << endl;
source.data = nullptr;
}
// Destructor
~Move()
{
if (data != nullptr)
cout << "Destructor is called for "
<< *data << endl;
else
cout << "Destructor is called"
<< " for nullptr "
<< endl;
delete data;
}
};
// Driver Code
int main()
{
// Vector of Move Class
vector<Move> vec;
// Inserting Object of Move Class
vec.push_back(Move{ 10 });
vec.push_back(Move{ 20 });
return 0;
}
output:
Constructor is called for 10
Move Constructor for 10
Destructor is called for nullptr
Constructor is called for 20
Move Constructor for 20
Constructor is called for 10
Copy Constructor is called -Deep copy for 10
Destructor is called for 10
Destructor is called for nullptr
Destructor is called for 10
Destructor is called for 20
I think what you are asking is why is the copy constructor called instead of your move constructor? It is because your move constructor is not noexcept. If you mark it as no except, the move constructor will be used during reallocation instead.
See this related answer for more information: https://stackoverflow.com/a/47017784/6324364
The common recommendation is that move constructors should be noexcept if at all possible. Many standard library functions will not use the move constructor if it could throw an exception.
If your question is instead about the order of constructor calls - that is just dependent on the implementation. An example implementation of push_back could be:
// The callsite of this function is where "Constructor is called for 20"
template<typename T>
void push_back(T&& value) {
// If the vector is full resize
if (size() == capacity()) {
auto* oldBuffer = m_buffer;
// allocate larger amount of space,
// increasing capacity but keeping size the same
// ...
// Here is your move constructor call
m_buffer[size()] = std::move(value);
// copy/move over old elements. This is your copy constructor
// If your move constructor was noexcept, it would be used.
// Otherwise the copy constructor is called.
// ...
m_size++;
// deallocate old buffer
// ...
} else {
m_buffer[size() - 1] = std::move(value);
m_size++;
}
}
The reason you seemingly get two constructor calls for 10 after the move constructor for 20 is because that is what your code does:
// Constructor
Move(int d)
{
// Declare object in the heap
data = new int;
*data = d;
cout << "Constructor is called for "
<< d << endl;
};
// Copy Constructor
Move(const Move& source)
// Here, your Copy constructor is calling the other constructor
: Move{ *source.data }
{
cout << "Copy Constructor is called -"
<< "Deep copy for "
<< *source.data
<< endl;
}
In your copy constructor you are explicitly calling your other constructor leading to the two log messages.
The implementation may do things in this order (move/copy new element, then move/copy old elements) as part of the strong exception guarantee provided by vector which says that the vector state will not be corrupted if copy/move of the new items fails. If it moved the old items first and then the new item constructor threw an exception, the vector state would be corrupted.
If you can add what you expected to happen in the code, maybe someone can give a better answer. As it stands, I don't fully understand what you are asking. You get those calls because that is how it is implemented.
Vector is stored as a one piece in memory, continously. When you add the second element to the vector, its current memory needs to be expanded to accomodate the newly added element. This will require your already existing elements to be copied somewhere else where enough memory is allocated to accomodate both (in your case) the first and second element. Take a look at what reserve is doing and how you can benefit from it. Or, similarly, if your vector is of fixed size, you may also take a look at array.

c++ - Destructor called on assignment

I'm still learning the basics of c++ so I may not have had the correct vocabulary to find the answer to my question but I couldn't find this mentioned anywhere.
If I have a class with a constructor and destructor why does the destructor get called on the new data when I am assigning to the class?
For example:
#include <iostream>
class TestClass {
public:
int* some_data;
TestClass() {
std::cout << "Creating" << std::endl;
some_data = (int*)malloc(10*sizeof(int));
}
~TestClass() {
std::cout << "Deconstructing" << std::endl;
free(some_data);
}
TestClass(const TestClass& t) : some_data{t.some_data} {
std::cout << "Copy" << std::endl;
}
};
int main() {
TestClass foo;
std::cout << "Created once" << std::endl;
foo = TestClass();
std::cout << "Created twice" << std::endl;
}
which prints:
Creating
Created once
Creating
Deconstructing
Created twice
Deconstructing
free(): double free detected in tcache 2
Aborted (core dumped)
So after following this in the debugger it appears the deconstructor is called on the newly created data which is confusing to me. Shouldn't the original data be freed once and then at the end of execution the new data should be freed? It seems like the original data is never freed like this.
Your object owns a raw pointer to allocated memory, but does not implement a proper copy constructor that makes an allocation and copies the data behind the pointer. As written, when you copy an object, the pointer is copied, such that now two objects point to the same address (and the old one that the just-assigned-to object is leaked.)
When the temporary goes out of scope, it deletes its pointer but the copy (foo) still points to it. When foo goes out of scope, it deletes the same pointer again, causing this double free error you're seeing.
If you need to write a destructor to clean up, you almost always need to also provide copy and assignment operations, or disable them.
SUGGESTIONS:
hold the pointer in a std::unique_ptr which will fail to compile if you try to copy it. This forces you to deal with the issue. Also, malloc and free are mainly for C or low-level C++ memory management. Consider using new and delete for allocations instead. (unique_ptr uses delete by default, not free, and you must not mix them.)
alternately, delete the copy constructor and assignment operator
also, consider when you want to move from an xvalue (temporary or moved lvalue), you can pilfer the allocation from the right-hand-side. So this class is a good candidate for move constructor and move assignment.
Most of the comments and a few details more in code:
#include <iostream>
#include <array>
#include <memory>
class TestClass
{
// members of a class should not be public
private:
// TestClass owns the data, this is best modeled
// with a unique_ptr. std::array is a nicer way of
// working with arrays as objects (with size!)
std::unique_ptr<std::array<int, 10>> some_data;
public:
TestClass() :
some_data{ std::make_unique<std::array<int,10>>() }
{
std::cout << "Creating" << std::endl;
// set everything in the array to 0
std::fill(some_data->begin(), some_data->end(), 0);
}
~TestClass()
{
std::cout << "Destructing" << std::endl;
// no need to manually delete a std::unique_ptr
// its destructor will free the memory
// and that will be called as part of this destructor
}
TestClass(const TestClass& t) :
// when you copy a class the copy should have its
// own copy of the data (to avoid deleting some data twice)
// or you must chose shared ownership (lookup std::shared_ptr)
some_data{ std::make_unique<std::array<int,10>>() }
{
std::cout << "Copy" << std::endl;
// copy data from t to this instances array
// (note this would not have been necessary
// it your array was just a non-pointer member,
// try that for yourself too.)
std::copy(some_data->begin(), some_data->end(), t.some_data->begin());
}
TestClass(TestClass&& rhs) :
some_data{ std::move(rhs.some_data) } // transfer ownership of the unique_pointer to this copy
{
std::cout << "Move" << std::endl;
}
// Important this assignement operator is used in your original code too
// but you couldn't see it!
TestClass& operator=(const TestClass& t)
{
some_data = std::make_unique<std::array<int, 10>>();
std::copy(some_data->begin(), some_data->end(), t.some_data->begin());
std::cout << "Assignment" << std::endl;
return *this;
}
};
int main()
{
TestClass foo;
std::cout << "Created once" << std::endl;
foo = TestClass();
std::cout << "Created twice" << std::endl;
TestClass bar{ std::move(foo) };
std::cout << "Moved" << std::endl;
}

Is Assignment Operator or Copy Constructor invoked for array/vector insertions?

Language: C++
My question is about whether the copy constructor or the assignment operator is called in the following situations. To precede, I understand the following:
MyClass a(3); // single param constructor
MyClass b(a); // copy constructor invoked
MyClass c = b; // copy constructor invoked
MyClass d; // default constructor
d = c; // assignment operator invoked
However, I was hoping someone could give a similar breakdown for these:
1) For lines 2-3, is assignment operator or copy constructor called?
MyClass arr[10];
arr[2] = a;
arr[5] = MyClass(1);
2) Constructor, then copy constructor? Or constructor, then assignment operator?
MyClass arr2[] = {MyClass(), MyClass(9)};
3) Assuming vector v's internal representation has space for one more object, is new element copied using assignment operator or copy constructor?
std::vector<MyClass> v;
v.push_back(MyClass(2));
...
...
4) Assuming vector v's internal representation is out of space and must realloc, are old elements copied using assignment operator, or copy constructor?
v.push_back(MyClass(2)); // Assuming vector is out of space; must realloc
MyClass arr[10];
Constructor for MyClass is called 10 times, as 10 objects of arr are created.
arr[2] = a;
Assignment operator is invoked, assigns arr[2] to a.
arr[5] = MyClass(1);
First single param constructor with parameter 1 is called and creates an object of MyClass. Then assignment operator is invoked.
MyClass arr2[] = {MyClass(), MyClass(9)};
Two constructors and only are called here. First the Myclass() and then "single param constructor" MyClass(9). The array declaration with initialization is not an assignment, cause no existing arrays members exists to assign to.
std::vector<MyClass> v;
Constructor for std::vector<MyClass> is called.
v.push_back(MyClass(2));
std::vector::push_back creates a copy of the class and stores it. So first MyClass(2) constructor is called, then copy constructor MyClass(const MyClass &) is called to copy the value. Then the copied object is stored.
Assuming vector v's internal representation is out of space and must realloc, are old elements copied using assignment operator, or copy constructor?
Copy operator is invoked for each member. So:
std::vector<MyClass> a;
Calls constructor for std::vector<MyClass>
a.push_back(MyClass(1));
Calls constructor for MyClass(1) and copies it using copy cosntructor MyClass(MyClass&).
After that if we add another element to the array:
a.push_back(MyClass(2));
Then MyClass(2) constructor is called, then copy constructor is called for MyClass(MyClass&) for the just constructed MyClass(2) object. Then the vector copy-constructs all existing members from the ned, so for the pre-existing object in the vector MyClass(1) already upped copy constructor is called.
Really, play with it a little. And insert cout everywhere to see it:
struct MyClass {
MyClass(int a = 0) : _a(a) {
_count = count++;
std::cout << __func__ << " "
<< _count << " "
<< this << " "
<< this->_a << "\n";
}
MyClass(const MyClass &old_obj) {
this->_a = old_obj._a;
std::cout << __func__ << "Copy "
<< _count << " "
<< this << " "
<< this->_a << " "
<< &old_obj << " "
<< old_obj._a << "\n";
}
void operator=(const MyClass &old_obj) {
this->_a = old_obj._a;
std::cout << "MyClass" << __func__ << " "
<< _count << " "
<< this << " "
<< this->_a << " "
<< &old_obj << " "
<< old_obj._a << "\n";
}
static int count;
int _count;
int _a;
};
int MyClass::count = 0;
When you have
type variable_name = some_value
then you are declaring a variable and will always be calling its constructor (if it has one). This is called copy initialization and this will never be assignment
So, in
MyClass arr[10]; // 1
arr[2] = a; // 2
arr[5] = MyClass(1); // 3
Line 1 creates an array of 10 MyClass and default constructs each of them. Lines 2 and 3 are assignment.
In
MyClass arr2[] = {MyClass(), MyClass(9)};
You initialize an array of 2 objects using the values in the *braced-init-list` as the initializers for the array members. There are many rules governing list initialization but the one thing they have in common is no assignment will happen, only constructor calls.
With
std::vector<MyClass> v;
v.push_back(MyClass(2));
Assuming the vector doesn't reallocate, you have a constructor call for MyClass(2) and then the element in the vector is copy constructed from that temporary object. If the vector has to grow then all of the current elements are copy/move constructed to a new buffer then the temporary is copied constructed at the end.

Copy constructor and returning passed argument

I'm reading Prata's C++ book, and when talking about copy constructors, it says that this constructor is invoked when:
Initializing a class object to the a class object of the same type.
Passing an object by value to a function.
Returning an object by value from a function.
Let say that we are working with a Vector class.
For understanding sakes, throughout the examples in the current chapter we included in the constructors/destructor definitions string outputs, to indicate which and when each of them is called.
For instance, if we have
int main()
{
Vector v1; // print "Default constructor called"
Vector v2(9, 5); // print "Constructor called"
Vector v3 = v1; // print "Copy Constructor called"
return 0;
}
And Destructor called would be printed in this case 3 times, when exiting main().
In order to check the 3 points above I've been playing with a dumb_display() function, changing the type of the formal parameter/return value. In doing so, I got confused about what is indeed happening under the hood.
Vector dumb_display(Vector v)
{
Vector test(45, 67);
cout << "In dumb_display() function" << endl;
cout << v << endl;
return v;
}
Here:
Every time we return by value the passed argument as in the above function (argument either passed by value or reference) the copy constructor gets called.
It makes sense. It satisfies point 3.
Every time we return an object defined in the function's body (e.g., changing return v; by return test;), the copy constructor isn't called.
Point 3 isn't satisfied.
I'm having a hard time trying to understand this behaviour.
I don't know whether this is correct, but I think (since an automatic storage duration object is created once for the duration of the function call) once test is created it, hasn't have to be created again, because the object "is already there". This brings the question:
Why does returning the passed argument call the copy constructor twice? Why does the same object have to be created twice for the duration of the call to the function?
#include <vector>
#include <type_traits>
#include <tuple>
#include <iostream>
using namespace std;
struct S {
S(){
cout << "default constructor" << endl;
}
S(S const &) {
cout << "copy constructor" << endl;
}
S(S &&) {
cout << "move constructor" << endl;
}
S & operator=(S const &) {
cout << "copy assignment" << endl;
return *this;
}
S & operator=(S &&) {
cout << "move assignment" << endl;
return *this;
}
};
S f() {
S s2;
cout << "In f()" << endl;
return s2;
}
S f2(S s) {
cout << "In f2()" << endl;
return s;
}
int main() {
cout << "about to call f" << endl;
S s2 = f();
(void)s2;
cout << endl << "about to call f2" << endl;
S s3 = f2(s2);
(void)s3;
}
results in:
about to call f
default constructor
In f()
about to call f2
copy constructor
In f2()
move constructor
In f(), the object is default constructed and return value optimization is used to actually construct it in place where it will actually end up -- in the s2 variable in main. No copy/move constructors are called.
In f2(), a copy is made for the input parameter for the function. That value is then moved into the variable s3 in main, again with return return value optimization.
live: https://wandbox.org/permlink/kvBHBJytaIuPj0YN
If you turn off return value optimization, you will see the results that you would expect from what your book says:
live: https://wandbox.org/permlink/BaysuTYJjlJmMGf6
Here's the same two examples without move operators if that's confusing you:
live: https://wandbox.org/permlink/c0brlus92psJtTCf
and without return value optimization:
live: https://wandbox.org/permlink/XSMaBnKTz2aZwgOm
it's the same number of constructor calls, just using the (potentially slower) copy constructor instead of the move constructor.
The copy constructor is called twice because it is first copied from the function into the temperary value (which is represented by the function call and is what the returned value is, then copied into the variable, requiring two copies. Since this is not very efficient, there is also a "move" constructor, which is only needed once.