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

  • Context:
  • Thread starter Thread starter JonnyG
  • Start date Start date
  • Tags Tags
    Change Value
Click For Summary

Discussion Overview

The discussion revolves around the behavior of unique pointers in C++, particularly in relation to their interaction with stack-allocated variables and dynamic memory allocation. Participants explore how unique pointers manage memory and the implications of using them with built-in pointers.

Discussion Character

  • Technical explanation
  • Conceptual clarification
  • Debate/contested

Main Points Raised

  • One participant notes that when using `std::unique_ptr q(new int(x));`, the unique pointer points to a dynamically allocated integer initialized with the value of `x`, not to `x` itself.
  • Another participant suggests that the compiler may treat `x` as a constant value, leading to confusion about the memory address being pointed to.
  • There is a discussion about whether `q(p)` should be `q(*p)`, with one participant arguing that `q(p)` is correct as it accepts a pointer parameter.
  • One participant explains that using `new int(x)` allocates memory on the heap, while `int *p = &x;` creates a pointer to a stack variable, leading to potential crashes when the unique pointer goes out of scope.
  • Another participant confirms that the unique pointer deletes the memory it manages when it goes out of scope, which can cause issues if it points to a stack-allocated variable.
  • There is mention of the need to access the underlying pointer using `q.get()` to modify the value it points to.

Areas of Agreement / Disagreement

Participants generally agree on the mechanics of how unique pointers work, particularly regarding memory allocation and scope. However, there are differing views on the implications of using unique pointers with stack-allocated variables, and the discussion remains unresolved regarding the best practices for using unique pointers.

Contextual Notes

Participants highlight limitations related to the understanding of smart pointers and their interactions with stack versus heap memory, as well as the potential for crashes when misusing unique pointers.

Who May Find This Useful

This discussion may be useful for programmers and students learning about memory management in C++, particularly those interested in the nuances of smart pointers and their proper usage.

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;
    count << 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:

count << *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;
    count << 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   Reactions: 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;
    count << 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:

count << *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;
    count << 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 count 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::count << x << std::endl;
}
 
  • Like
Likes   Reactions: 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;
    count << 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;
    count << 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   Reactions: 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   Reactions: Jarvis323 and jedishrfu

Similar threads

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