-1

I expect following code to fail (in main function), but it works:

class Response {
public:
    Response() {}

    void displayInfo() {
        cout << "Hello!" << endl;
    }
};

class HttpClient
{
public:
    HttpClient(Response& response) : m_response(&response) {
        m_response = &response;
    }

    Response* getResponse() {
        return m_response;
    }

private:

    Response *m_response;
};


HttpClient* createClient()
{
    Response response;
    HttpClient *clnt = new HttpClient(response);
    clnt->getResponse()->displayInfo();
    return clnt;
}


int main()
{
    HttpClient* client = createClient();

    // ------------------------------------------
    // I expect getResponse()->displayInfo() to fail, since "response" object
    // passed as argument to HttpClient (in createClient function) goes out of the scope and should be deleted.

    client->getResponse()->displayInfo();
}

So I've created local variable response in the createClient function. Then this local variable is passed as constructor argument (reference) to HttpClient.

This argument is assigned to the member Response *m_response.

So as I understand, m_response holds reference to response local variable.

But when response local variable goes out of the scope, I still can access to it via m_response (call method of m_response object).

I expect that m_response should refer to some garbage since response went out of the scope.

Why does it work?

Teimuraz
  • 8,795
  • 5
  • 35
  • 62
  • 2
    Undefined behavior is undefined :P – Rakete1111 Mar 10 '18 at 19:32
  • 2
    Undefined behaviour always works as expected. – Andrei Damian Mar 10 '18 at 19:32
  • 1
    C++ puts a lot of the burden of making sure your code is correct on you (the programmer) - there is no automatic check whether the memory a (raw) pointer is referring to still contains a valid object – UnholySheep Mar 10 '18 at 19:33
  • @nullqube what are you talking about? There is no reference counting involved here and the `Response` object that was used in `createClient` clearly went out of scope – UnholySheep Mar 10 '18 at 19:37
  • Yeah I kinda was right, check this out : https://stackoverflow.com/questions/3097593/what-happens-when-c-reference-leaves-its-scope – nullqube Mar 10 '18 at 19:54
  • https://stackoverflow.com/questions/3097806/const-reference-to-temporary-oddity – nullqube Mar 10 '18 at 19:55

1 Answers1

2

Why does it work?

It works basically because the implementation let it, possibly because it has not reused/recycled the memory the local variable was using yet. The behavior here is undefined, so anything can happen. It can work like this, but it doesn't have to.

Also, I would better define what you mean by "fail" when you access that pointer to memory that is now gone. In general, there are strong and weaker "failure" guarantees in the C++ standard. The strong failure guarantees are well-defined (e.g., throw an exception, return an error code). But there are a lot of weak failures that end up causing undefined behavior that you have to be careful about when writing code. A lot of pointer operations have failure end up being undefined behavior, so if you want a stronger failure guarantee I would switch to smart pointers and the like.

Daniel
  • 1,291
  • 6
  • 15
  • Ok, so it is not "correct code" right? – Teimuraz Mar 10 '18 at 19:34
  • Depends on what you mean by "correct code". The syntax of the program is correct, but its memory usage and expectations are not. – Daniel Mar 10 '18 at 19:35
  • @Teimuraz no it is not correct code. The response object goes out of scope. The fact that you're getting the "correct" results is an unfortunate side effect of undefined behavior (it "works" by accident). The `HttpClient` constructor should have made a deep copy of `response` if they intended to `createClient` in that way. – Justin Randall Mar 10 '18 at 19:48