0

I crashed application every time I ran the code below. During debugging, I saw that the str object was self-destructing itself after the second line in main(). And it's quite a mystery for me. Try run it yourself:

#include<iostream>

class String {
private:
    char* string = nullptr;
    int length = 0;

public:
    String(const char str[]) {
        for (length; str[length] != '\0'; ++length);

        string = new char[length + 1]{};

        for (int i{}; i < length; ++i)
            string[i] = str[i];

        string[length] = '\0';
    }

    ~String() {
        delete[] string;
    }

    auto print() {
        for (int i{}; i < length; ++i)
            std::cout << string[i];
        std::cout << '\n';
        return *this;
    }

    auto getStrPtr() {
        return string;
    }
};

int main() {
    String str("123");
    auto strPtr{ str.print().getStrPtr() };
    strPtr[0] = '3';
}

Am I missing something?

Note on line 2 in main(): I am trying to print the str's string array and then, since print() returns *this, I can chain methods and am calling a function that returns string's pointer. But, even if in debugger it all executes perfectly, I have no idea why the hell str object deconstructs itself after.

sirkostya009
  • 43
  • 1
  • 7

1 Answers1

0

str object is not destroyed on the second line of main. The temporary copy of str is destroyed.

Temporaries are destroyed at the end of full expression. This is normal.


Your class deletes a pointer member in destructor, but fails to maintain class invariant of uniqueness of that pointer. The behaviour of the program is undefined when the destructor of str deletes the same pointer value as the destructor of the temporary object deletes. Behaviour is undefined even before that when strPtr[0] = '3'; indirects through the pointer that was deleted in the destructor.

Solution: Don't use owning bare pointers. Use smart pointer or container instead. std::string seems appropriate here.


But why that temporary object was created in the first place?

Because you return a String object in print. You initialise it with *this, and therefore that object is a copy. You don't use the returned object to initialise a variable, so a temporary object is materialised.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • And don't use `auto` everywhere for no good reason. It conceals bugs. Like how `print()` returns by value from a class that has broken copy semantics. – Asteroids With Wings May 18 '20 at 17:06
  • @AsteroidsWithWings I don't think `auto` hides that here. The function returns `auto`, therefore it clearly returns by value. What it does hide is that the function returns `String` specifically rather than some other value type. Expecting `auto` to be a reference is less reasonable that expecting `String` to be a reference - outside of context - since latter could in theory be an alias of reference. That said, avoid type aliases for references except in cases where they are conventional. – eerorika May 18 '20 at 17:07
  • 1
    Surely the OP intended to return a `String&`, and either didn't realise or didn't spot that their `auto` doesn't achieve that goal. We see it all the time. Sure, it's "clear", if you already know it and don't miss it! – Asteroids With Wings May 18 '20 at 17:08
  • But why that temporary object was created in the first place? – sirkostya009 May 18 '20 at 17:29
  • @AsteroidsWithWings `Sure, it's "clear", if you already know it and don't miss it!` So, the problem isn't that `auto` "hides" anything, but that OP is using something that they don't understand. – eerorika May 19 '20 at 12:24
  • Of course it's not `auto`'s "fault", but it _does_ lull many people into a false sense of security due to its false appearance of simplicity. – Asteroids With Wings May 19 '20 at 13:18
  • @AsteroidsWithWings In my opinion, making programs appear unnecessarily complex is not worth it just to make beginners feel the complexity. There must be a better way to achieve that. – eerorika May 19 '20 at 13:28
  • In my opinion, `String print()` shows the bug far more clearly. I don't think spelling a six-letter return type is particularly "complex". But your mileage may vary. – Asteroids With Wings May 19 '20 at 13:32