Is it safe to push_back an element from the same vector?
It looks like http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-closed.html#526 addressed this problem (or something very similar to it) as a potential defect in the standard:
1) Parameters taken by const reference can be changed during execution
of the functionExamples:
Given std::vector v:
v.insert(v.begin(), v[2]);
v[2] can be changed by moving elements of vector
The proposed resolution was that this was not a defect:
vector::insert(iter, value) is required to work because the standard
doesn't give permission for it not to work.
Does push_back in vector insert at the same location?
for(int i=0; i<vec.size(); ++i) // --> Deep copy
{
Example newE(*(vec[i]));
newVec.push_back(&newE);
}
In this code you make a copy of vec[i]
to Example newE
. Then you push_back
the address of newE
to the newVec
vector. Then the newE
object goes out of scope and is destroyed, so you end up having a pointer to garbage inside newVec
.
If you want a deep copy of vector content, and you want to store owning pointers to objects, consider using vector of smart pointers, e.g. vector<shared_ptr<Example>>
.
In this case, you can simply copy the vectors with operator=
, and the reference counts of the shared_ptr
s will be automatically updated.
Yoy may want to consider also the simpler design of just having vector<Example>
(without pointer indirection).
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).
vector function push_back keeps rewriting the value to the same slot in memory
You're creating a new vector
in each call to createTable
, not reusing an existing vector
; you're not constantly inserting into v[0]
, you're constantly replacing v
with a whole new vector that only has a single element. The second call to createTable
should probably just be a direct call to v.push_back(insertedString);
.
Alternatively, remove the vcreate
declaration and actually use the v
passed into the function instead (which is still wasteful, because it's constantly copying and replacing vector
s instead of pushing onto an existing one directly, but it would at least be logically correct).
Insert or push_back to end of a std::vector?
After all, they do the same thing. Don't they?
No. They are different. The first method using std::vector::push_back
will undergo several reallocations compared to std::vector::insert
.
The insert
will internally allocate memory, according to the current std::vector::capacity
before copying the range. See the following discussion for more:
Does std::vector::insert reserve by definition?
But is there any difference in performance?
Due to the reason explained above, the second method would show slight performance improvement. For instance, see the quick benck-mark below, using http://quick-bench.com:
See online bench-mark
Or write a test program to measure the performance(as @Some programmer dude mentioned in the comments). Following is a sample test program:
#include <iostream>
#include <chrono>
#include <algorithm>
#include <vector>
using namespace std::chrono;
class Timer final
{
private:
time_point<high_resolution_clock> _startTime;
public:
Timer() noexcept
: _startTime{ high_resolution_clock::now() }
{}
~Timer() noexcept { Stop(); }
void Stop() noexcept
{
const auto endTime = high_resolution_clock::now();
const auto start = time_point_cast<microseconds>(_startTime).time_since_epoch();
const auto end = time_point_cast<microseconds>(endTime).time_since_epoch();
const auto durationTaken = end - start;
const auto duration_ms = durationTaken * 0.001;
std::cout << durationTaken.count() << "us (" << duration_ms.count() << "ms)\n";
}
};
// Method 1: push_back
void push_back()
{
std::cout << "push_backing: ";
Timer time{};
for (auto i{ 0ULL }; i < 1000'000; ++i)
{
std::vector<int> vec = { 1 };
vec.push_back(2);
vec.push_back(3);
vec.push_back(4);
vec.push_back(5);
}
}
// Method 2: insert_range
void insert_range()
{
std::cout << "range-inserting: ";
Timer time{};
for (auto i{ 0ULL }; i < 1000'000; ++i)
{
std::vector<int> vec = { 1 };
int arr[] = { 2,3,4,5 };
vec.insert(std::end(vec), std::cbegin(arr), std::cend(arr));
}
}
int main()
{
push_back();
insert_range();
return 0;
}
release building with my system(MSVS2019:/Ox /std:c++17, AMD Ryzen 7 2700x(8-core, 3.70 Ghz), x64 Windows 10)
// Build - 1
push_backing: 285199us (285.199ms)
range-inserting: 103388us (103.388ms)
// Build - 2
push_backing: 280378us (280.378ms)
range-inserting: 104032us (104.032ms)
// Build - 3
push_backing: 281818us (281.818ms)
range-inserting: 102803us (102.803ms)
Which shows for the given scenario, std::vector::insert
ing is about 2.7
times faster than std::vector::push_back
.
See what other compilers(clang 8.0 and gcc 9.2) wants to say, according to their implementations: https://godbolt.org/z/DQrq51
Is it safe to push_back 'dynamically allocated object' to vector?
If all you care about is exception-safety of this operation:
v.reserve(v.size()+1); // reserve can throw, but that doesn't matter
v.push_back(new Foo); // new can throw, that doesn't matter either.
The issue of a vector having responsibility for freeing the objects pointed to by its contents is a separate thing, I'm sure you'll get plenty of advice about that ;-)
Edit: hmm, I was going to quote the standard, but I actually can't find the necessary guarantee. What I'm looking for is that push_back
will not throw unless either (a) it has to reallocate (which we know it won't because of the capacity), or (b) a constructor of T throws (which we know it won't since T is a pointer type). Sounds reasonable, but reasonable != guaranteed.
So, unless there's a beneficial answer over on this question:
Is std::vector::push_back permitted to throw for any reason other than failed reallocation or construction?
this code depends on the implementation not doing anything too "imaginative". Failing that, your solution from the question can be templated up:
template <typename T, typename Container>
void push_back_new(Container &c) {
auto_ptr<T> p(new T);
c.push_back(p.get());
p.release();
}
Usage then isn't too tedious:
struct Bar : Foo { };
vector<Foo*> v;
push_back_new<Foo>(v);
push_back_new<Bar>(v);
If it's really a factory function rather than new
then you could modify the template accordingly. Passing a lot of different parameter lists in different situations would be difficult, though.
Vector push_back() and direct assignment using [] give different results
vector<string> board(n);
fills the vector already with n
elements. If you now add additional! elements with push_back
, you have a vector with two times elements. The first half are already in from the constructor of std::vector
and the second half pushed in later.
If you use the default constructor
vector<string> board;
in combination with push_back
, you will get the same results as with your example code.
For large vectors the solution with upfront initialization of n
elements and access via operator[]
can be much faster, because there is no need of reallocation and copy operations inside the vector. If speed is important: measure!
Vector.push_back() adds same Element while reading from File
As mentioned in the comments, you are pushing the pointers back not the actual strings. To get the actual strings you can do this:
void readFileToVec()
{
ifstream file;
file.open ("rb");
vector<string> v;
string word;
while (file >> word)
{
v.push_back(word);
}
}
This will work if the elements are all strings and are seperated by a space,tab, or newline. If your words are seperated by anything other than one of these three (for example a list of words separated by commas) then you can use getline and specify the separator.
In any case, reading about C++ streams and the difference between C-style strings and STL strings would be worthwhile if you intend to do this sort of thing with C++ again. You are using C Strings and old school FILE which is part of the C Library while C++ provides you with utilities to make your life easier. File streams and C++ strings are great examples of such utilities.
push_back() is not adding element to the vector? (C++ Tree Traversal)
You're ignoring the results from each recursion. You should be doing this:
vector<int> inorderTraversal(TreeNode *root)
{
vector<int> order;
if (root != nullptr)
{
order = inorderTraversal(root->left);
cout << "pushing back : " << root->val << std::endl;
order.push_back(root->val);
auto tmp = inorderTraversal(root->right);
order.insert(order.end(), tmp.begin(), tmp.end());
}
return order;
}
Much More Efficient
That said, if you counted the number of local vectors created in this, though short, they will be many (as many as there are nodes in your tree, in fact). You can eliminate all of those middle-men vectors by providing a shim between the actual traversal and the creation of the order vector:
void inorderTraversal_v(TreeNode const *root, std::vector<int>& order)
{
if (root != nullptr)
{
inorderTraversal(root->left, order);
order.push_back(root->val);
inorderTraversal(root->right, order);
}
return order;
}
std::vector<int> inorderTraversal(TreeNode const *root)
{
std::vector<int> order;
inorderTraversal_v(root, order);
return order;
}
Doing this creates a single vector, and in so doing eliminates (N-1) temporary vectors along the way, where N is the number of nodes in the tree.
Related Topics
Variable Assignment in an "If" Condition
How to Check If Enum Value Is Valid
What Happens to Uninitialized Variables? C++
Random Array Generation with No Duplicates
How to Leverage Qt to Make a Qobject Method Thread-Safe
A Base Class Pointer Can Point to a Derived Class Object. Why Is the Vice-Versa Not True
Boost C++ Serialization Overhead
(How) How to Count the Items in an Enum
How to Store Objects of Differing Types in a C++ Container
Extracting C/C++ Function Prototypes
Why Doesn't Narrowing Conversion Used with Curly-Brace-Delimited Initializer Cause an Error
Using Member Variable in Lambda Capture List Inside a Member Function