A unique pointer cannot change the value of the original object?

  • Thread starter Thread starter JonnyG
  • Start date Start date
  • Tags Tags
    Change Value
Click For Summary
The discussion centers on the behavior of `std::unique_ptr` in C++. When a unique pointer is initialized with `new int(x)`, it points to a dynamically allocated memory containing the value of `x`, not to `x` itself, which is why changes to the unique pointer do not affect `x`. In contrast, when a unique pointer is initialized with a built-in pointer to `x`, it attempts to manage the memory of `x`, leading to a crash when the unique pointer goes out of scope and tries to delete the stack-allocated `x`. The proper way to modify the value pointed to by a unique pointer is to use the `get()` method to access the raw pointer. Understanding these concepts is crucial for effectively using smart pointers in C++.
JonnyG
Messages
233
Reaction score
45
When I run this simple code:

C++:
int main() {
    int x = 45;
    std::unique_ptr<int> q(new int (x));
    *q = 3;
    cout << x << endl;
    
}

45 is printed on the console. I expected this to print 3 to the console. It prints 3 when I use a built-in pointer. Does this mean that unique pointer doesn't actually point to x itself (i.e. doesn't hold x's memory address)? If in the above code I add this line to the end:

cout << *q.get();

Then it prints 3 to the console. This means that the built-in pointer that is in q points to an object that was indeed changed to point to a memory address that contains 3 in it (but this pointer was supposed to point to x!).

Furthermore, when I run this:

C++:
int main() {
    int x = 45;
    int *p = &x;
    std::unique_ptr<int> q(p);
    *q = 3;
    cout << x << endl;
    
}

Then the console prints 3, as I had wanted, but then the program crashes. There is obviously something about unique pointers (and shared pointers in general) that I am not understanding. I'd appreciate some help.
 
Technology news on Phys.org
Maybe the compiler has treated x as a constant value and replaced usages of it by a constant.

In the q(p) shouldn't that be q(*p) ?

This stack discussion may help:

https://stackoverflow.com/questions/16894400/how-to-declare-stdunique-ptr-and-what-is-the-use-of-it

Here's a brief tutorial on unique_ptr usage:

https://thispointer.com/c11-unique_ptr-tutorial-and-examples/

They have an example of using ( new int(3) ) which creates a pointer to a location containing three.

So in your case the compiler replaced x by 25 (call by value) stored 25 somewhere and provided a pointer to the 25 instead. Changing x then wasn't reflected in the unique_ptr.

Using a debugger on your code would confirm that.
 
Last edited:
jedishrfu said:
In the q(p) shouldn't that be q(*p) ?

I get a compilation error when I run that, but I think I figured out the problem. When I type new int(x) (in q's constructor), this constructs a pointer to an integer of value 45 that has been dynamically-allocated in the heap. This doesn't mean that the dynamically-allocated built-in pointer is pointing to x - it's just pointing to some memory address that also has the value of 45 in it. This is why I cannot change the value of x through q. This is different than me typing:

C++:
int x = 45;
int* p = &x;
std::unique_ptr<int> q(p);

This code first constructs a built-in pointer on the stack that is then passed to the unique_ptr constructor. But the unique_ptr constructor requires a dynamically-allocated pointer, which is why the above code crashes.

At least that's what I think. I will take a look at the tutorial you linked and see if I can confirm this.
 
Yeah, I think you're right.

It's the call by value scheme used by C/C++ in method calls.

The x value is placed on the stack and the new int() is called, it pops the value and then allocates memory for it from the heap (it must do this because stack data is volatile) and returns a pointer to the heap value.
 
  • Like
Likes JonnyG
jedishrfu said:
Yeah, I think you're right.

It's the call by value scheme used by C/C++ in method calls.

The x value is placed on the stack and the new int() is called, it pops the value and then allocates memory for it from the heap (it must do this because stack data is volatile) and returns a pointer to the heap value.

Now I see that to change the value of the object that my unique_ptr q is pointing to, I must write:

*q.get() = whatever value

I can only access the built-in pointer that q is wrapped around by using the get() method.
Thank you for your help.
 
jedishrfu said:
In the q(p) shouldn't that be q(*p) ?
I don't believe so. I see at least 5 constructors for the unique_pointer template class, all of which have a pointer parameter or no parameters at all.

JonnyG said:
When I run this simple code:

C++:
int main() {
    int x = 45;
    std::unique_ptr<int> q(new int (x));
    *q = 3;
    cout << x << endl;
   
}

45 is printed on the console. I expected this to print 3 to the console. It prints 3 when I use a built-in pointer. Does this mean that unique pointer doesn't actually point to x itself (i.e. doesn't hold x's memory address)? If in the above code I add this line to the end:

cout << *q.get();

Then it prints 3 to the console. This means that the built-in pointer that is in q points to an object that was indeed changed to point to a memory address that contains 3 in it (but this pointer was supposed to point to x!).

Furthermore, when I run this:

C++:
int main() {
    int x = 45;
    int *p = &x;
    std::unique_ptr<int> q(p);
    *q = 3;
    cout << x << endl;
   
}

Then the console prints 3, as I had wanted, but then the program crashes. There is obviously something about unique pointers (and shared pointers in general) that I am not understanding. I'd appreciate some help.
I haven't explored the various kinds of "smart" pointers much, so can't enlighten you with regard to what you don't understand. At any rate, your code doesn't crash for me, using VS 2017.

My code adds an include directive and scope operators on cout and endl, but is otherwise the same as yours:
C++:
#include<iostream>
int main() 
{
    int x = 45;
    int *p = &x;
    std::unique_ptr<int> q(p);
    *q = 3;
    std::cout << x << std::endl;
}
 
  • Like
Likes jedishrfu
JonnyG said:
When I run this simple code:

C++:
int main() {
    int x = 45;
    std::unique_ptr<int> q(new int (x));
    *q = 3;
    cout << x << endl;

}

new int( x ) allocates space on the heap to store an int, and initializes that int to the value of x, and returns a pointer to the address of the newly allocated int (which is different than the address of x).

JonnyG said:
C++:
int main() {
    int x = 45;
    int *p = &x;
    std::unique_ptr<int> q(p);
    *q = 3;
    cout << x << endl;

}

In this example, you do create a smart pointer with the address of x. But smart pointers delete the pointer they manage when they go out of scope (in their destructor). x itself is an automatic object on the stack that is destroyed when the function exits. q also goes out of scope, so x is 'destroyed' and also delete is called on its address. That's why it crashes.

Anyways, it never makes sense to call delete on the address of a stack object.
 
Last edited:
  • Like
Likes jbunniii, JonnyG and jedishrfu
Good explanation @Jarvis323. My version did throw an exception, but only after the final brace, which I didn't check for in the debugger.
 
  • Like
Likes Jarvis323 and jedishrfu

Similar threads

Replies
3
Views
1K
  • · Replies 1 ·
Replies
1
Views
1K
Replies
5
Views
2K
  • · Replies 13 ·
Replies
13
Views
3K
  • · Replies 15 ·
Replies
15
Views
4K
  • · Replies 19 ·
Replies
19
Views
3K
Replies
12
Views
2K
Replies
12
Views
3K
Replies
4
Views
2K
  • · Replies 23 ·
Replies
23
Views
2K