Is std::vector copying the objects with a push_back?
Yes, std::vector<T>::push_back()
creates a copy of the argument and stores it in the vector. If you want to store pointers to objects in your vector, create a std::vector<whatever*>
instead of std::vector<whatever>
.
However, you need to make sure that the objects referenced by the pointers remain valid while the vector holds a reference to them (smart pointers utilizing the RAII idiom solve the problem).
Does std::vector's push_back create a deep copy of the argument?
Here's a little testing program to demonstrate the data-sharing properties of cv::Mat objects (which are matrix headers) in special!
int main()
{
// create input of size 512x512
cv::Mat input = cv::imread("../inputData/Lenna.png");
// create a second input of size 256x256
cv::Mat modifiedInput;
cv::resize(input, modifiedInput, cv::Size(256,256));
std::vector<cv::Mat> images;
// first element will be a "deep copy" where the matrix elements will be copied to a new memory location and a new header will be created, referecing those matrix elements.
images.push_back(input.clone());
// 6 times copy the "input" to "images".
// All the copies will (deep) copy the matrix header but they will share the matrix elements (because their memory LOCATION will be copied)
for(unsigned int i=0; i<6; ++i)
images.push_back(input);
// now some experiments:
// draw a circle to input variable. At this point it should share it's matrix elements with images[1-5]
cv::circle(input, cv::Point(100,100), 30, cv::Scalar(0,0,0), -1);
// draw a circle to a vector element:
cv::circle(images[5], cv::Point(300,100), 30, cv::Scalar(0,0,0), -1);
// use a openCV function that will allocate new memory, if the destination dimensions don't fit:
// to a mat whose dimensions fit:
// remember that input.size() == vector[0..5].size
// compute median blur and target one of the matrices that share their data at the moment:
cv::medianBlur(input, images[3], 11);
cv::imshow("0", images[0]);
cv::imshow("1", images[1]);
cv::imshow("2", images[2]);
cv::imshow("3", images[3]);
cv::imshow("4", images[4]);
cv::imshow("5", images[5]);
cv::waitKey(0);
At this time it's looking like this: All matrices share their element's data except the first matrix because there a deep-copy was forced with .clone()
.
now continue with this:
// to a mat whose dimensions don't fit (new memory will be allocated, not shared by the other matrix headers anymore):
// images[3] will not share the data with other matrix headers afterwards
cv::medianBlur(modifiedInput, images[3], 11);
// now images[3] and images[4] will share matrix elements
images[4] = images[3];
cv::circle(images[4], cv::Point(128,128), 20, cv::Scalar(255,255,255), 3);
// create a deep-copy of 256x256 input to overwrite images[5] (not modifying any other image's matrix elements)
images[5] = modifiedInput.clone();
cv::circle(images[5], cv::Point(0,0), 30, cv::Scalar(0,255,0), -1);
cv::imshow("0", images[0]);
cv::imshow("1", images[1]);
cv::imshow("2", images[2]);
cv::imshow("3", images[3]);
cv::imshow("4", images[4]);
cv::imshow("5", images[5]);
//cv::imshow("input", input);
//cv::imwrite("../outputData/MainBase.png", input);
cv::waitKey(0);
return 0;
}
looks like this:
This time, the call of medianBlur
did NOT share the data with all the other matrices, because the destination-image's dimensions DID NOT FIT, so new memory had to be allocated for images[3]
within the medianBlur method. So images[3] referenced different data elements aferwards!
All this might be a little tricky because the user might not see directly, which function calls will allocate new data and which ones don't, so if you want to be sure to allocate new data, you should do this in beginning for each mat, or use an empty mat as destination (or don't share any data in the beginning).
One more thing:
cv::Mat emptyMat;
std::vector<cv::Mat> images(n, emptyMat); // insert n copies of emptyMat header
// or
for(unsigned int i=0; i<n; ++i)
images.push_back(emptyMat) // same result
this is both save to use so that not data is shared, because all emptyMat doesn't have any data in the beginning, so no data can be shared. Whenever any data is assigned to any of the vector elements, the other's don't know about it and so they won't share that data.
// BUT:
cv::Mat notEmptyMat = cv::Mat::zeros(height, width, type);
std::vector<cv::Mat> images(n, notEmptyMat ); // insert n copies of emptyMat header which references the assigned zeroes data of size width x height
// or
for(unsigned int i=0; i<n; ++i)
images.push_back(notEmptyMat ) // same result
Here, data is shared and whenever you change the DATA of one of those matrices, the other ones will be changed, too. But obviously, if you assign new data memory to one of those matrices, the other ones still reference their other data memory.
Unable to avoid copying while pushing objects with copy-construcor into a vector
std::move
isn't useful here. The temporary Vertex
object is already a prvalue, so casting it to an xvalue doesn't change anything. The class has no move constructor, so copy initialisation cannot move; it has to copy. The implicit move constructor has been inhibited by the user defined copy constructor. Although, the move constructor couldn't be any faster than the copy constructor for this class anyway.
The way that emplace_back
works is that it forwards the arguments to the constructor of the element. If the argument that you pass is an object of the element type, then you invoke the constructor that accepts another instance of the class - that is the copy constructor (or the move constructor for classes that have it).
Instead of creating a temporary Vertex
object, and passing it as an argument to emplace_back
, you should pass the three size_t
objects that can be forwarded to the constructor Vertex(size_t, size_t, size_t)
. This way you can avoid copying (and moving) of the Vertex
object entirely:
vert.emplace_back(1, 2, 3);
vert.emplace_back(4, 5, 6);
vert.emplace_back(7, 8, 9);
How can I push_back/copy custom type ( array) object to vector?
std::vector<foo>
means "vector of foo values", you can't push_back(new foo)
into it as new foo
is a pointer (foo*
). You'd need to push_back(foo{})
which default-constructs a foo
instance (a value). This doesn't work because:
std::vector<T>::push_back
requires thatT
is MoveInsertable (in this particular case)foo
is a C-array, and C-arrays are not MoveInsertable
In general, C-arrays don't work well with std::vector
. You can use std::array
instead, because it is MoveInsertable.
#include <vector>
#include <array>
#include <iostream>
using foo = std::array<std::array<std::pair<float, float>, 8>, 8>;
std::vector<foo> v;
v.push_back(foo{});
std::cout << v[0][0][0].first << "\n";
In this case you don't need your copy
function as std::array
will do copying
Live Demo
c++ push_back copying object instead of reference
Nothing in your code stores references. Your code copies a node because you allocate a new node in std::make_shared
and invoke the copy constructor.
std::vector<Node> nodes;
It's local to your function. It would be impossible to keep either pointers (shared or not) or references to elements of this vector. Perhaps you want to use a vector of shared pointers instead:
std::vector<std::shared_ptr<Node>> nodes;
Bear in mind that shared_ptr doesn't work well in presence of cyclic referenced. If your data structure is a general graph, then perhaps shared_ptr is not appropriate for storing neighbours. You may want to consider weak_ptr instead (you will have to keep a container of shared pointers to all nodes separately).
How to push_back a class object into a std::vector?
"however when i try to push_back to a vector in MAIN function, it
return 0 0 0 (B default values)"
This is because of not initializing the member variables of B
class. This should be done when you push_back
the a new A
object to the std::vector
like follows:
vecA.push_back(A("name", "path", B(15, 04, 2018)));
If your doubt is how to to use push_back
is, above will certainly clarified it.
Update: I have set the copy constructor
and copy assignment operator
to default
and it worked. Live action: https://www.ideone.com/TlmAm2
#include <iostream>
#include <string>
#include <vector>
class Date
{
public:
Date(int day = 0, int month = 0, int year = 0)
: _day(day), _month(month),_year(year) {}
~Date(){}
int get_day() { return _day; }
int get_month() { return _month; }
int get_year() { return _year; }
void writestuff()
{
std::cout << _day << "/" << _month << "/" << _year<< std::endl;
}
private:
int _day;
int _month;
int _year;
};
class Adatok
{
public:
Adatok(std::string name, std::string path, Date date )
: _name(name), _path(path), _date(date) {}
~Adatok(){}
void writestuff()
{
std::cout<<_name<<" "<<_path<<" ";
_date.writestuff();
std::cout<<std::endl;
}
//change in copy constructor and copy assignment operator
Adatok(const Adatok& other) = default;
Adatok& operator= (const Adatok& other) = default;
private:
std::string _name;
std::string _path;
Date _date;
};
void database(std::string temp, std::vector<Adatok> my_vec)
{
for(auto& it: my_vec)
it.writestuff();
}
int main(int argc, char **argv)
{
std::vector<Adatok> my_vec;
int year = 2018, month = 04, day = 15;
std::string name = "name1", path = "path1";
my_vec.push_back(Adatok(name,path,Date(day,month,year)));
database("something", my_vec);
return 0;
}
When std::vector push_back() the object which has the reference member
You're getting this behavior because you are initializing your 'ref' member to a value that is on the stack, then the default copy constructor is copying that into the vector.
For example, in my debugger the value I have for ref is:
+ &myVector[1].ref 0x00eff80c {2.0000000000000000} double *
+ &myVector[1] 0x00126940 {a=2.0000000000000000 ref=2.0000000000000000 }
+ myVector { size=0x00000002 } std::vector<myClass,std::allocator<myClass> >
+ &nIter 0x00eff8f0 {0xffffffff} int *
You can see that myVector[1].ref
is not inside myVector[1]
as you'd expect, and is, in fact, on the stack. You can see that nIter and ref are only 57 bytes apart:
&nIter - (int*)&myVector[0].ref 57
If you want to see how this is implicitly happening you can delete your copy constructor:
myClass(myClass const &rhs) = delete;
inside myClass and you'll get an error at push_back.
Another option is to write your own copy constructor:
myClass(myClass const &rhs) : ref(a) {
a = rhs.a;
}
If you debug this you'll see that the values are correct, and that the memory locations of each ref are now inside the bounds of the myClass objects.
Finally you might be able to use emplace_back
instead of push_back
, which will construct myClass
directly in the vector's memory instead of calling the copy ctor, though I wouldn't recommend this as it leaves this ref copy bug.
also don't forget the assignment operator if you go the copy ctor route:
https://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)
e.g.
myClass baz;
baz = myVector[0];
this will invoke operator= and not the copy ctor. My compiler (visual studio c++ latest) automatically deletes operator= if you declare a copy ctor, so it would catch this, but your compiler may not.
vector::push_back using std::move for internal reallocations
According to [vector.modifiers]/2 if the element type of std::vector
is not copy-insertable and not nothrow-move-constructible, then an exception thrown from a move constructor of the element type results in an unspecified state of the container.
std::vector
must prefer the copy constructor if the type isn't nothrow-movable, so that the exception guarantees can be preserved, but if that isn't possible, it is impossible to give strong exception guarantees.
push_back to std::vector, the copy constructor is repeatedly called
First of all you have to remember that unless you reserve memory for the vector, it needs to allocate and reallocate memory as its capacity needs to increase.
The reallocation basically allocates new memory, then copies the element in the vector to the new memory.
Furthermore, when you push a value into a vector, that value needs to be copied into the vector. You can avoid that by emplacing the value (which means it's constructed in place in the vector), or by moving the value when you push it back.
Related Topics
May Std::Vector Make Use of Small Buffer Optimization
Copy Constructor Is Not Inherited
How to Get Current Timestamp in Milliseconds Since 1970 Just the Way Java Gets
In What Ways Do C++ Exceptions Slow Down Code When There Are No Exceptions Thown
Getline Not Working Properly? What Could Be the Reasons
How to Use MACro Argument as String Literal
Why Cannot a Non-Member Function Be Used for Overloading the Assignment Operator
Uses of a C++ Arithmetic Promotion Header
Identifying Primitive Types in Templates
What Is an In-Place Constructor in C++
Why Static Variable Needs to Be Explicitly Defined
How Would I Load a Png Image Using Win32/Gdi (No Gdi+ If Possible)