string s; &s+1; Legal? UB? - c++

Consider the following code:
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
string myAry[] =
{
"Mary",
"had",
"a",
"Little",
"Lamb"
};
const size_t numStrs = sizeof(myStr)/sizeof(myAry[0]);
vector<string> myVec(&myAry[0], &myAry[numStrs]);
copy( myVec.begin(), myVec.end(), ostream_iterator<string>(cout, " "));
return 0;
}
Of interest here is &myAry[numStrs]: numStrs is equal to 5, so &myAry[numStrs] points to something that doesn't exist; the sixth element in the array. There is another example of this in the above code: myVec.end(), which points to one-past-the-end of the vector myVec. It's perfecly legal to take the address of this element that doesn't exist. We know the size of string, so we know where the address of the 6th element of a C-style array of strings must point to. So long as we only evaluate this pointer and never dereference it, we're fine. We can even compare it to other pointers for equality. The STL does this all the time in algorithms that act on a range of iterators. The end() iterator points past the end, and the loops keep looping while a counter != end().
So now consider this:
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
string myStr = "Mary";
string* myPtr = &myStr;
vector<string> myVec2(myPtr, &myPtr[1]);
copy( myVec2.begin(), myVec2.end(), ostream_iterator<string>(cout, " "));
return 0;
}
Is this code legal and well-defined? It is legal and well-defined to take the address of an array element past the end, as in &myAry[numStrs], so should it be legal and well-defined to pretend that myPtr is also an array?

It is legal and not UB to have a pointer to "one past the end" of an array, and any single object can be treated as if it were in an array of length 1; however, you need to use ptr + 1 instead due to the technicality of &ptr[1] dereferencing and then taking the address. This also applies to &array[size] becoming array + size.
What you have will work as you expect on all platforms of which I'm aware, but given how easy it is to use the unambiguously correct form, I see no reason not to do that instead.

The C++ standard in 5.6/4 "Additive operators" says:
For the purposes of these operators, a pointer to a nonarray object behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.
The C99 standard 6.5.6/7 says essentially the same.

Related

Is there some way to use std::remove_if on std::string_view iterators?

I'm wanting to effectively trim an already created std::string_view using an iterator that doesn't point to the trimmed characters thanks to std::remove_if(). However, I can't use std::remove_if() on a std::basic_string_view::iterator directly because that's really a std::basic_string_view::const_iterator and std::remove_if() can't take non-moveable iterators as arguments.
The only workaround I've though of is casting the std::string_view to a std::string and then taking the iterator. Here's an example of that:
#include <string>
#include <string_view>
#include <algorithm>
#include <locale>
int main() {
std::string_view foo{"Whitepace...\nThe Final Frontier"};
const auto is_space{
[](const auto& character) {
return std::isspace(character, std::locale{});
}
};
// Doesn't compile
//auto without_conversion{
// std::remove_if(foo.begin(), foo.end(), is_space)
//};
// Works, for the most part.
auto with_conversion{
std::remove_if(std::string{foo}.begin(), std::string{foo}.end(), is_space)
};
But this kinda defeats the whole point of using std::string_view, as a string_view constructed from this iterator wouldn't be viewing the original string.
Is there some (preferably elegant) way to do this while keeping the view on the original string? Perhaps some way to make the string_view iterator non-const?
If your goal is to trim a string_view of spaces, and store the result in a std::string, then you should choose the appropriate algorithm that allows const iterators.
One such algorithm is std::copy_if:
#include <iostream>
#include <string_view>
#include <algorithm>
#include <iterator>
#include <cctype>
int main()
{
std::string_view foo{"Whitepace...\nThe Final Frontier"};
std::string result;
std::copy_if(foo.begin(), foo.end(), std::back_inserter(result), [](char ch)
{ return !std::isspace(static_cast<unsigned char>(ch)); });
std::cout << result;
}
Output:
Whitepace...TheFinalFrontier
std::string_view is a constant view of the string sequence.
For example, begin returns a const_iterator.
https://en.cppreference.com/w/cpp/string/basic_string_view/begin
Maybe you will have better luck with std::span, however take into account that literals in the program are always immutable.
You have to make a copy first anyway.
Also your last line doesn't do what you think because you are iterating over different temporaries, even if it compiles.
The correct code is, for example:
std::string FOO = foo;
auto with_conversion{
std::remove_if(FOO.begin(), FOO.end(), is_space)
};
In other words, the whole idea of your program (that you can modify a "program" string) is flawed in the first place.

What's 'mymap[1];' instruction where mymap is std::map?

I found a code which use the instruction mymap[1];. Did any one know the meaning of it?
Here is a sample code which compiles successfully:
#include <iostream>
#include <map>
using namespace std;
int main()
{
std::map<int,int> mymap;
mymap[1];
cout<<mymap[1];
return 0;
}
mymap[1] gives you the element with the key 1. For example, you could assign to it: mymap[1] = something;, or print it: std::cout << mymap[1];.
If the element is missing, it's inserted automatically. The new element is value-initialized, which for scalar types essentially means zeroed.
As you noticed, doing just mymap[1]; is allowed. It inserts the element if it's missing, and does nothing else.

Segmentation Fault in C++ - Vectors

#include <cmath>
#include <cstdio>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int a, b;
cin>>a;
vector<int> numbers;
for(int i=0; i<a; i++)
{
cin>>b;
numbers.push_back(b);
}
int c,d,e;
cin>>c;
numbers.erase(numbers.begin()+c-1);
cin>>d>>e;
numbers.erase(numbers.begin()+d-1, numbers.end()+e);
cout<<numbers.size();
for(int x : numbers)
cout<<x<<" ";
return 0;
}
Hello everyone,
I am learning c++ and writing a very simple program, but this code is giving "Segmentation Fault" as error. I really could not figure out why this is happening.
Thank you.
This line
numbers.erase(numbers.begin()+d-1, numbers.end()+e);
cannot be correct. Incrementing the end iterator never gets you a valid iterator. It is not quite clear what you want to do, but if you want to erase elements in the range of indices [d,e) then that would be
numbers.erase(numbers.begin()+d, numbers.begin()+e);
Note: No +1 needed on the first, because the first is inclusive. And you get an iterator to the e-th element by incrementing the begin iterator not the end iterator (well... I assume the common 0-based counting, ie the "first" element is the 0th element ;).
Also, as mentioned in comments, you should check if the user entered values are in range, before calling erase. erase does no bounds-checking. If you pass invalid iterators your get undefined behavior.

Comparing unordered_map vs unordered_set

First of all, what is the main difference between them?
The only thing i've found is that unordered_set has no operator [].
How should i access an element in unordered_set, since there is no []?
Which container is using random access to memory(or both)?
And which one of them faster in any sense or using less memory?
They are nearly identical. unordered_set only contains keys, and no values. There is no mapping from a key to a value, so no need for an operator[]. unordered_map maps a key to a value.
You can use the various find methods within unordered_set to locate things.
you can use iterators to access elements.
unordered_set <string> u{
"Dog",
"Cat",
"Rat",
"Parrot",
"bee"
};
for(auto& s:u){
cout << s << ' ';
}
unordered_set<string>::const_iterator point = u.find("bee");
How should I access an element in unordered_set (C++17)?
In C++ 17 a new function extract is added to unordered_set.
Specially, this is the only way to take move only object out of the set.
https://en.cppreference.com/w/cpp/container/unordered_set/extract
For example if you want third element of your unordered set.
Advance the iterator
std::advance(it,2);
Then extarct the value
s.extract(it).value();
Here is the complete code. try on any C++17 compiler.
#include <iostream>
#include <string>
#include <unordered_set>
#include <iterator>
int main()
{
//CREATE AN OBJECT
std::unordered_set<std::string> s;
//INSERT DATA
s.insert("aee");
s.insert("bee");
s.insert("cee");
s.insert("dee");
//NEED TO INCLUDE "iterator" HEADER TO USE "std::advance"
auto it = s.begin();
std::advance(it,2);
//USING EXTRACT
std::string sval = s.extract(it).value();
std::cout<<sval;
}
Note: if queried for out of bound index, nothing happens. No result.
Try changing your code
//ONLY FOUR ELEMENTS
std::advance(it,8);
//USING EXTRACT
std::string sval = s.extract(it).value();

Segmentation fault while initializing vector by an initialized array in C++

I wanted to use the sort() in the algorithm library in C++. I could find examples for sorting vectors only, thus I am trying to initialize a vector by an initialized array. When executing I am getting a segmentation fault and couldn't figure out what is wrong here in the code I wrote.
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int n,k,packet[1000],min=0;
scanf("%d",&n);
scanf("%d",&k);
for (int i = 0; i < n; ++i)
{
scanf("%d",&packet[i]);
cout<<i<<endl;
}
cout<<"debug";
vector<int> packets(packet,packet+n);
vector<int>::iterator start,stop;
sort(packets.begin(),packets.begin()+n);
min=*(packets.begin())- *(packets.end());
cout<<min;
for (vector<int>::iterator it=packets.begin(); it!=packets.end()-k; ++it)
{
printf("%d ",*it );
if((*(it+k) - *it)<min)
{
start=it;
stop=it+k;
}
}
printf("%d\n",*stop- *start );
return 0;
}
*(packets.end())
packets.end() returns an iterator to the element, following the last element of the vector.
Attempting to derefenrence it causes Undefined Behavior.
The comments explain that you can use sort with an array just fine (if you look at http://en.cppreference.com/w/cpp/algorithm/sort you'll see that sort takes two arguments that: -RandomIt must meet the requirements of ValueSwappable and RandomAccessIterator.. Plain pointers fulfill this requirement).
In your example, the segfault happens because you try to dereference a valid but undereferencable iterator (the iterator returned by 'end()' in: min=*(packets.begin())- *(packets.end());. Basically it returns an iterator that points to after the last element of the vector. If you want to get an iterator to the last element, you can use rbegin() but of course you need to make sure that the vector is not empty first).
You could have seen this quite easily by running your code under a debugger, you'd see that the segmentation fault had nothing to do with the call to sort