How to insert a duplicate element into a vector? - c++

I'm trying to insert a copy of an existing vector element to double it up. The following code worked in previous versions but fails in Visual Studio 2010.
#include <iostream>
#include <vector>
using namespace std;
int main(int argc, char* argv[])
{
vector<int> test;
test.push_back(1);
test.push_back(2);
test.insert(test.begin(), test[0]);
cout << test[0] << " " << test[1] << " " << test[2] << endl;
return 0;
}
Output is -17891602 1 2, expected 1 1 2.
I've figured out why it's happening - the vector is being reallocated, and the reference becomes invalid before it's copied to the insertion point. The older Visual Studio apparently did things in a different order, thus proving that one possible outcome of undefined behavior is to work correctly and also proving that it's never something you should rely on.
I've come up with two different ways to fix this problem. One is to use reserve to make sure that no reallocation takes place:
test.reserve(test.size() + 1);
test.insert(test.begin(), test[0]);
The other is to make a copy from the reference so that there's no dependency on the reference remaining valid:
template<typename T>
T make_copy(const T & original)
{
return original;
}
test.insert(test.begin(), make_copy(test[0]));
Although both work, neither one feels like a natural solution. Is there something I'm missing?

The issue is that vector::insert takes a reference to a value as the second parameter and not a value. You don't need the template to make a copy, just use a copy constructor to create another object, which will be pass by reference. This copy remains valid even if the vector is resized.
#include <iostream>
#include <vector>
using namespace std;
int main(int argc, char* argv[])
{
vector<int> test;
test.push_back(1);
test.push_back(2);
test.insert(test.begin(), int(test[0]));
cout << test[0] << " " << test[1] << " " << test[2] << endl;
return 0;
}

I believe this is defined behavior. In §23.2.3 of the 2011 C++ standard, table 100 lists sequence container requirements and there is an entry for this case. It gives the example expression
a.insert(p,t)
where a is a value of X which is a sequence container type containing elements of type T, p is a const iterator to a, and t is an lvalue or const rvalue of type X::value_type, i.e. T.
The assertion for this expression is:
Requires: T shall be CopyInsertable into X. For vector and deque, T shall also be CopyAssignable.
Effects: Inserts a copy of t before p.
The only relevant vector specific quote I could find is in §23.3.6.5 paragraph 1:
Remarks: Causes reallocation if the new size is greater than the old capacity. If no reallocation happens, all the iterators and references before the insertion point remain valid.
Although this does mention the vector being reallocated, it doesn't make an exception to the previous requirements for insert on sequence containers.
As for working around this issue, I agree with #EdChum's suggestion of just making a copy of the element and inserting that copy.

Related

Why is std::vector::insert a no-operation with an empty initializer-list?

In the follwoing code:
#include <iostream>
#include <vector>
int main()
{
std::cout<<"Hello World";
std::vector<std::vector<int>> v;
while(v.size() <= 2){
v.insert(v.begin(),{}); //1
std::cout << "!";
}
return 0;
}
The output is getting increasingly aggressive with every iteration, because the v.size() never increases, despite the insert operation.
However, when the initializer_list has an element in it, or replaced with a temporary, the cycle runs as many times as expected.
...
v.insert(v.begin(),{0}); //1
...
...
v.insert(v.begin(),std::vector<int>()); //1
...
Why is that? Shouldn't there be a compile error if implicit conversion fails?
Your code is asking to inert as many items as there are in the initialiser list into the vector. Since there are no items in the initialiser list nothing gets inserted.
I'm not sure what you were expecting instead, perhaps you were expecting a vector to be created from the initialiser list and that vector inserted, i.e.
v.insert(v.begin(),std::vector<int>{})
but that doesn't happen because vector<T>::insert has an overload that takes an initializer_list<T> directly (and which behaves as I described above).

User input in default constructors (C++). Can this be done?

This was the question: Write a program in C++ to enter two sequence separately and find total length of both sequences using constructor.
This is the program that I wrote. It runs but did I use constructors properly? Can we do this? Can we take user input in default constructors?
#include <iostream>
#include <string.h>
using namespace std;
class merge {
private:
int i;
char seq1[5];
int len, len1, len2;
char seq2[5];
public:
merge();
};
merge::merge() {
cout << "Enter first sequence: ";
cin >> seq1;
cout << "Enter second sequence: ";
cin >> seq2;
len1 = strlen(seq1);
cout << "Length of first sequence: " << len1 << "\n";
len2 = strlen(seq2);
cout << "Length of first sequence: " << len2 << "\n";
strcat (seq1, seq2);
cout << "Merged sequence: " << seq1 << "\n";
len = strlen(seq1);
cout << "Total length: " << len;
}
int main() {
merge o;
}
User input in default constructors (C++). Can this be done?
Technically yes. Constructor body is mostly the same as any other function, and I/O is possible.
Practically, I/O in a constructor would be a bad design.
So we can, but we do not do this.
Can we take user input in default constructors?
Yes you can do it, but you shouldn't.
There are many ways to explain why. For example, consider what it means to be default-constructible. From cppreference about the named requirement DefaultConstructible:
Specifies that an instance of the type can be default constructed.
Requirements
The type T satisfies DefaultConstructible if
Given
u, an arbitrary identifier
The following expressions must be valid and have their specified
effects
T u The object u is default-initialized
T u{} The object u is value-initialized or aggregate-initialized.
T() / T{} A temporary object of type T is value-initialized or aggregate-initialized.
Your merge is DefaultConstructible. But is it really?
Consider what happens when you add a second constructor:
merge::merge(std::string seq1, std::string seq2);
Now I can choose whether I want to use the default constructor to take input from user, or get the sequences from elsewhere and call the other constructor. Sounds good, no?
(It isn't. It just helps me to emphasize the problem with your default constructor in the following examples. Bear with me.)
Code that is fine with a default constructible type T, but not quite with your merge is...
example std::vector
using T = merge;
std::vector<T> v(10);
v[0] = T("1,2,3,4","4,5,6,7,8");
// ...
Because I want to avoid reallocations of the vector and because I know that T can be default constructed, I created a vector with 10 elements even though I want to create the actual elements only later. I didn't want to ask for user input 10 times when I wrote std::vector<T> v(10); but thats the only way to resize a vector that contains elements of your class.
example: std::map
std::map<int,T> m;
m[1] = T("1,2,3,4","4,5,6,7,8");
I want to add an element to the map (if it didnt exist before). std::map::operator[] tries to find an element with the given key (1). It does not find one, hence it inserts a new element with that key and a default constructed T. Then it returns a reference to that T.
I could have used insert, but I was lazy and used []. As a consequence, this code asks the user for input, but thats not what I wanted.
Here is a demo of the two issues I tried to explain above: https://godbolt.org/z/fj5qoa
Formally, your merge is default-constructible, but for most practical purposes it isn't. A default constructor is expected to construct an object in a default state. Reading user input is surprising and many types and algorithms that require that your type is default constructible will not work as expected, even though you provided a default constructor.

How to make unordered_map<string*, V> hash by value instead of reference?

I have the following
The two equivalent strings bar and bartest do not map to the same value in unordered_map. How can I make this happen?
Of course they don't map to the same value, const string* is a pointer type and since you call new string twice, you end up with two separate objects that don't have memory identity (the pointers are not equal).
What's worse, you leak both of them at the end of your program.
What's (arguably) worse still, owning raw pointers and naked new calls are considered harmful in modern c++.
Luckily it's all fixed with unordered_map<string, int> - no pointers required whatsoever.
Your C++ is in fact "Java-- + C".
Remove all those silly pointers.
All you need is unordered_map<string,int> and use plain values instead of heap-allocated "news"
just do
#include <unordered_map>
#inclide <string>
#include <iostream>
int main()
{
unordered_map<string,int> mymap;
mymap["bar"] = 5;
mymap["bartest"] = 10;
std::cout << mymap["bar"] << ' ' << mymap["bartest"] << '\n';
return 0;
}

Can I rely on std::map::operator[] to touch?

I have a C++ program in which I want to insert default values for any keys missing in a std::map. I'm thinking the easiest way to do this would be to use std::map::operator[]() like the POSIX touch command - that is, to leave the value unchanged if it already exists, but to create it if it doesn't. For example,
#include <map>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector<int> keys = {0, 1};
map<int, int> m;
m[1] = 5;
m[2] = 12;
for (const int i : keys)
{
m[i]; // touch value
}
for (auto const & kv : m)
{
cout << kv.first << ", " << kv.second << endl;
}
}
Can I be sure that the compiler won't optimize out the m[i]; statements, since I'm not "doing" anything with them? (Not explicitly assigning to, not reading from.)
Yes you can be sure. Optimizing the call away would change the observable behavior of your program, and the compiler is not allowed to do this (except in the case of RVO).
This is known as the as-if rule.
Yes, you can be sure. It's perhaps more intuitive when you consider that the line in question is equivalent to this:
m.operator[](i);
…and you don't expect arbitrary function calls to be optimised out of your program, if they do anything.
The [] operator does indeed default-construct the value that would be at that key's location if you do not assign it something.
Reference Link
If k does not match the key of any element in the container, the
function inserts a new element with that key and returns a reference
to its mapped value. Notice that this always increases the container
size by one, even if no mapped value is assigned to the element (the
element is constructed using its default constructor).

cin to vector of bools

I have this code:
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector <bool> v;
cin >> v[0];
return 0;
}
Why can't I do that? The compiler won't compile that, but I have other variable types in the vector, it will work just fine. What's the problem with this?
It's because std::vector<bool> is a specialization and doesn't act like a vector at all. This is widely recognized to be a major flaw in the Standard.
In order to save memory, vector<bool> stores each element as a single bit. But bits aren't individually addressable, so operator[] can't return a bool& reference connected to a bit. Instead it returns vector<bool>::reference... and cin doesn't provide function overloads to deal with this.
(juanchopanza correctly points out that your vector didn't have an element zero. But even if it did via resize or other mechanism, the fact that operator[] doesn't return a reference still gets in the way.)
At the time you call v[0], the vector has zero size, so you are accessing out of bounds. This is undefined behaviour.
Furthermore, std::vector<bool> is a specialization which has strange behaviour due to the fact that it does not hold individual bool elements. Its operator[] returns a kind of proxy object, the call to that operator may not do what you expect. It should be used with care, or not used at all.
You can solve the problem by reading a value into a local variable and then pushing it into the back of the vector, as in this working example (similar live demo here):
#include <vector>
#include <iostream>
int main()
{
std::vector<bool> v;
std::cout << std::boolalpha;
v.push_back(true);
std::cout << v[0] << std::endl;
bool b;
cin >> b;
v[0] = b;
std::cout << v[0] << std::endl;
}
This should work:
#include <iomanip>
...
bool a;
cin >> boolalpha >> a;
v.push_back(a);
(In addition to the problem mentioned by Ben Voigt, your current code isn't safe with types other than bool because your vector is empty when you're accessing v[0].)