-3

I was trying to use char* pointers to refer to strings and vector<char> & dynamic arrays & I have a doubt with the following results :-

CODE 1:-

#include <iostream>
#include <string>
using namespace std;
int main()
{
    cout<<"executing...\n";
    string s="abcde";
    char *c=&s[0];
    cout<<c<<"\n";
    s.~string();
    cout<<c<<"\n";
    cout<<"executed";
    return 0;
}

The output of this code is :-

executing...
abcde
abcde
executed 

CODE 2:-

#include <iostream>
#include <vector>
using namespace std;
int main()
{
    cout<<"executing...\n";
    vector<char> v {'a','b','c','d','e'};
    char *p=&v[0];
    cout<<p<<"\n";
    v.~vector();
    cout<<p<<"\n";
    cout<<"executed";
    return 0;
}

The output for this code is :-

executing...
abcde

executed 

CODE 3 (with dynamic arrays):-

#include <iostream>
using namespace std;
int main()
{
    cout<<"executing...\n";
    char* c=new char[20] {'a','b','c','d','e'};
    char *p=c;
    cout<<p;
    delete[] c;
    cout<<"\n"<<p<<"\n";
    cout<<"executed";
    return 0;
}

The output for this code is similar to CODE 2:-

executing...
abcde

executed 

I want to know why CODE 1 produces an output different from CODE 2 & CODE 3 ? What problem does string have that it behaves differently from vector<char> & dynamic arrays ?

Anwesha
  • 728
  • 1
  • 7
  • 18
  • I guess it is because 'strings' are reference counted in C++ – DevInd Oct 12 '15 at 16:00
  • 13
    All three are UB, their output does not matter. – Baum mit Augen Oct 12 '15 at 16:01
  • 4
    All three snippets cause undefined behaviour, so all your expectations have no base. – Ulrich Eckhardt Oct 12 '15 at 16:01
  • @CppNITR They used to be: the may no longer be. – edmz Oct 12 '15 at 16:09
  • what is the meaning of this `~`. I have never seen this before... – 463035818_is_not_an_ai Oct 12 '15 at 16:13
  • 2
    @tobi303 This is explicitly calling the destructor, in this case triggering even more UB as it will now be called twice. You *really* rarely need this. – Baum mit Augen Oct 12 '15 at 16:15
  • @BaummitAugen ups of course. I should have known that, but really think I never saw it used like this before. Calling it on an object before it is going out of scope looks kinda weird. – 463035818_is_not_an_ai Oct 12 '15 at 16:19
  • gentlemen, this is called EXPERIMENTING WITH LANGUAGE :P – Anwesha Oct 12 '15 at 16:21
  • 2
    @tobi303 It is not just weird, it is plain wrong and triggers UB unless the object is trivially destructible, in which case the the destructor does nothing anyways, which makes the whole thing pretty nonsensical. – Baum mit Augen Oct 12 '15 at 16:21
  • Can anyone explain me how this an undefined behaviour ? – DevInd Oct 12 '15 at 16:22
  • @black how can you say that they may no longer be – Ankit Acharya Oct 12 '15 at 16:24
  • @Anwesha no need to use capitals... you are free to experiment whatever, but then you have to accept when the outcome is something that in non-experimantal code should be avoided – 463035818_is_not_an_ai Oct 12 '15 at 16:24
  • 1
    @CppNITR Calling the destructor of an object twice (here: once explicitly and once when the object goes out of scope) is UB unless the object is trivially destructible, which `std::string` and `std::vector` are not. Accessing the internal memory of a `std::string` or `std::vector` after it was destructed is also UB, same as accessing `delete[]`d memory. – Baum mit Augen Oct 12 '15 at 16:26
  • @CppNITR memory access on an object after its destructor was called or the memory explicitly freed. Also multiple calls to the destructor of a single object - explicit with .~string() and then implicit by the compiler. – josefx Oct 12 '15 at 16:26
  • 1
    @Anwesha This experiment makes about as much sense as *"Why does it hurt more when I hit myself in the head with a hammer than it does with a bottle of whisky?"*. – Baum mit Augen Oct 12 '15 at 16:27
  • @AnkitAcharya: As far as I'm aware, the only widely used reference counted standard strings were GNU libstdc++. They are not reference counted anymore. Can't see why that would matter anyway. It's still undefined behavior, whether the strings are ref counted or not. – Benjamin Lindley Oct 12 '15 at 16:28
  • @AnkitAcharya c++11 does not allow astring[0]='c' to replace the underlying array. This makes it impossible to share the string contents internally. – josefx Oct 12 '15 at 16:38
  • 3
    @Anwesha The problem with experimenting with C++ this way is that you will find a thousand and more things where the code behaves weirdly, all because of undefined behavior. All the time "experimenting" could / should be applied to actually learning the language properly. – PaulMcKenzie Oct 12 '15 at 16:49

2 Answers2

2

All the snippets of code access data that has been deleted, which has no defined behavior. Therefore, any further assumption is meaningless and left to the single case. Whether you're accessing a vector, char*, string there's no difference: it's always the same violation.

edmz
  • 8,220
  • 2
  • 26
  • 45
  • 1
    what if strings are actually reference counted as @CppNITR said. it would mean that CODE 2 & CODE 3 are causing UB but not CODE 1. – Anwesha Oct 12 '15 at 16:28
  • `string` *may not* be reference counted anymore since C++11. – edmz Oct 12 '15 at 16:28
  • 1
    @Anwesha No it would not. UB does not depend on the implementation, but on the standard. – Baum mit Augen Oct 12 '15 at 16:28
  • i guess Scott Meyers has said in Effective STL that strings are reference counted. – DevInd Oct 12 '15 at 16:31
  • See [this](https://stackoverflow.com/questions/12199710/legality-of-cow-stdstring-implementation-in-c11?lq=1). And Effective STL is old. – edmz Oct 12 '15 at 16:33
  • 2
    @black cpp.sh/6arhl see this – DevInd Oct 12 '15 at 16:38
  • the array stored by string is still intact because char pointer is pointing to it. this shows that string must be reference counted @BenjaminLindley – DevInd Oct 12 '15 at 16:52
  • 1
    @CppNITR: Huh? What pointer are you talking about? The string is still intact because you didn't do anything that would cause it not to be intact. A better test for reference counted strings would be something like this: http://cpp.sh/52x3 -- Notice the string arrays both have distinct addresses. And after a modification to one string, they both have the same address that they did before. – Benjamin Lindley Oct 12 '15 at 16:54
  • @Anwesha reference counting std::strings still require at least one valid std::string instance to point to reference the internal C array. In this case there is only one std::string "s" and its destructor is called before the second access, so there is no valid reference left. Anyway reference counting was an implementation detail and you should not rely on these. – josefx Oct 12 '15 at 17:01
  • 2
    @CppNITR: Oops, I was looking at a different page than the one you made (I left out the last l). I see the pointer you are talking about, but I don't see the output you describe. And it wouldn't matter what the output is anyway, because it's undefined behavior. You seem to be saying, with this example, not that strings are reference counted, but raw pointers too? That is obviously false. If you are printing the contents of a deallocated memory location, and it prints what was there before, that simply means that the characters were not cleaned up. They aren't required to be. – Benjamin Lindley Oct 12 '15 at 17:14
0

Well I guess this example is good enough to show that your objects of string & vector are deleted twice hence leading to undefined behaviour :-

#include <iostream>
using namespace std;

class X
{
    int x;
    public:
    X()
    {
        cout<<"constructing\n";
    }

    // other member functions...

    ~X()
    {
        cout<<"destroying\n";
    }
};

int main()
{
    X object;
    object.~X();
    return 0;
}

Output will be :-

constructing
destroying
destroying

When behaviour is undefined there is no use of thinking about "WHY SUCH AN OUTPUT", etc stuffs !! Even I had a doubt regarding the reference counting of C++ strings but as many people are saying strings are no longer reference counted so CODE 1 is also producing undefined behaviour. However I liked you experimenting with codes. It's necessary to learn a language properly. Keep it up !!!

DevInd
  • 1,645
  • 2
  • 11
  • 17
  • 1
    Do you have any site or book which states that strings arent reference counted anymore ? – Ankit Acharya Oct 12 '15 at 18:13
  • @AnkitAcharya The only implementation that I know of that did that was libstdc++, and that changed in version 5. You will find it in their changelog. – Baum mit Augen Oct 12 '15 at 20:06
  • @CppNITR even with reference counted strings CODE 1 would have been undefined. Reference counting requires at least one valid std::string instance referencing the "abcde" string, which is no longer the case after s.~string(). – josefx Oct 12 '15 at 22:36