0

i have that c++ code

#include <iostream>
#include <vector>
#include <memory>

struct Foo{
    int* a;

    Foo(std::vector<int> vec)
    {
        a = &(vec.front());
    }
};

struct Bar {
    std::unique_ptr<int> a;

    Bar(std::vector<int> vec)
    {
        a = std::make_unique<int>(vec.front());
    }
};

int main() {
    std::vector<int> vec = {42};
    Foo foo(vec);
    Bar bar(vec);
    // returns 0, but should 42
    std::cout << *foo.a << std::endl;
    // but this returns 42
    std::cout << *bar.a << std::endl;

    return 0;
}

why does *foo.a returns 0, instead of 42? What am i doing wrong?

Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
  • 2
    If [so] doesn't allow you to do what you want, you're most likely wrong. Make a [mcve]. – user202729 Mar 24 '18 at 08:41
  • 1
    Although in this particular case... – user202729 Mar 24 '18 at 08:41
  • Have you tried stepping through your program with a debugger, watching the variables as they change? – MivVG Mar 24 '18 at 08:41
  • The code is not that long. Then, you should explain in words what your code does. The comments in the code can as well be in the question statement. – user202729 Mar 24 '18 at 08:42
  • 1
    Make a pointer to a local variable... undefined behavior, everything can happen. [See this](https://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope). – user202729 Mar 24 '18 at 08:44

4 Answers4

2

Change line Foo(std::vector<int> vec) to Foo(std::vector<int>& vec) and it will work fine. See it here working.

The problem is that vec is a local variable and it is no more valid once function call returns.

cse
  • 4,066
  • 2
  • 20
  • 37
1

why does *foo.a returns 0, instead of 42?

Because undefined behaviour means your program can do everything. It may crash, it may print 42, it may print 0, it may print nothing. The C++ language specification has no rules for what will happen.

The undefined behaviour is caused by trying to access a pointer to an object which has already been destroyed. In Foo(std::vector<int> vec), you get a local copy of the vector. The copy is destroyed when the constructor ends. a cannot be used for anything afterwards. You cannot even safely compare it to another pointer, or to nullptr, much less dereference it! All you could do it with it is set a new pointer value.

*foo.a is an attempt to read the pointer value. In this moment, undefined behaviour has happened.

The smart-pointer version does not have undefined behaviour because std::make_unique<int> creates a dynamically allocated copy of the integer. That copy is managed internally by a, and is only destroyed when a itself is destroyed.

Christian Hackl
  • 27,051
  • 3
  • 32
  • 62
0

The problem is that you pass the vector by value, creating a copy of the contents. Note that this vector goes out of scope immediately after the execution of your constructor. This way, your a pointer is left pointing to nothing. Usually this would crash the program, but in some environments it just gives '0'.

To fix your problem, pass the vector by reference or const reference. See also this link for more info on passing by reference.

MivVG
  • 679
  • 4
  • 16
-3

Both variants are erroneous. You pass a copy of the Vector to the constructor, take a pointer to the first element, and after the constructor returns that copy is destroyed, leaving the pointer invalid. unique_ptr automatically destroys the pointer you give it, and vector destroys its memory too, so you free the same memory twice in the 2nd example.

Erlkoenig
  • 2,664
  • 1
  • 9
  • 18