-1
#include <iostream>
#include <string>
using std::string;
int main(){
    string s;
    std::cout << "size:" << s.size() << " "
                      << "capacity:" << s.capacity() << std::endl;
    std::cout << s[3] << std::endl;
    return 0;
}

I defined a empty string object, named s. Both the s.size() and s.capacity() are zero, but when accessing the element s[3],there is no segment fault, why ?

G.yang
  • 347
  • 2
  • 10
  • 4
    Undefined behavior is all you can expect in this case. This may or may not crash your program. That uncertainty is exactly why it is strongly advised *not* to do it! – StoryTeller - Unslander Monica Jan 08 '17 at 13:07
  • 1
    Definitely undefined behavior. what might make this not crash is maybe the small string optimization of the standard library implementation that you're using – PeterT Jan 08 '17 at 13:09

4 Answers4

5

Putting aside the fact that (as explained by the others) this is UB and that (speaking academically) anything could happen, the specific reason in this specific case that you did not get a Segmentation Fault is that the operating system does not detect all memory accesses outside of your allocated objects -- it only detects when your invalid memory access is so wrong that it is to 0x0 or another page of virtual memory entirely, one with which your process was not furnished. That is the only level of "automatic" memory error detection that exists.

For more than that, your computer would have to inspect every memory access and compare it against the map of blocks allocated in the free store (which is very slow; you can do this during debugging using tools like electric fence and valgrind, though) or you would have to add index checking yourself (e.g. using .at() instead of []).

C++ is a safe language to some degree, but there are still plenty of features that feel "bare-bones", inherited from C, where you maintain responsibility for knowing what you're doing, and cannot rely on your computer to tell you when you've done it wrong.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
2

segfault is not bound to happen when you access a memory you don't own, it can happen.

CIsForCookies
  • 12,097
  • 11
  • 59
  • 124
1

You're invoking something called undefined behaviour. It could crash, it could do nothing, it could do what you intended. Nothing is guaranteed. The behaviour is quite literally "undefined".

OMGtechy
  • 7,935
  • 8
  • 48
  • 83
1

Because many errors in C++ have no defined effects but instead result in undefined behaviour. Passing an impossible index to std::string's operator[] is an example of such an error. Anything or nothing can happen.

This is because requiring compilers to create programs which perform all kinds of error checking at runtime would severely reduce the usability of C++ in usage scenarios where the overhead of error checking would be unacceptable. Generally, if you want runtime error checking like this in C++, then you have to ask for it (and pay for it).

A rather simplistic way would be to use the at member function, which is required to throw exceptions for illegal string indices. But how would you "handle" an exception like this, other than with an ugly catch in main which logs an error and quits?

An illegal string index should be treated as a bug which has to be fixed, not "handled" at runtime. Fortunately, there are ways to tell compilers to add detection of a wrong operator[] at runtime. Here's some more information:


Note that only size is relevant to determine whether accessing an element is undefined behaviour or not. capacity is not.

Community
  • 1
  • 1
Christian Hackl
  • 27,051
  • 3
  • 32
  • 62