0

I have read the documentation about initializing unique pointer here . I tried to declare the unique pointer the same way (see unique_ptr<int> temp1 {&h} ,I did not see this type of declaration in the docs though,just experimenting) i declare a non-smart pointer . The idea behind carrying out this experiment was to see how the std::unique_ptr::get() method works. Here is the code :

#include<iostream>
#include<stdio.h>
#include<memory>

using namespace std  ;
int main(){

int h {100};
unique_ptr<int> temp1 {&h};

cout<<"temp1.get() :"<<temp1.get()<<endl;
cout<< "&h : "<<&h<<endl;
cout<<"*temp : "<<*temp1<<endl;
    return 0 ; 
}

The code compiles and i get the following output :

temp1.get() :0x7ffd4322c5cc
&h : 0x7ffd4322c5cc
*temp : 100
/home/abhishek/.codelite/tmp/abhishek/codelite-exec.sh: line 3:  7889 Segmentation fault      (core dumped) ${command}
Hit any key to continue...

I can see the std::unique_ptr::get() returns the address of the managed object , which is same as &h. What is the error saying here ? Although assigning address to the smart pointer has been discussed here . It does not answer my question.

warrior_monk
  • 383
  • 2
  • 14
  • 9
    The `unique_ptr` is trying to `delete` something not allocated with `new`. – KamilCuk Dec 29 '19 at 03:28
  • "*Although assigning address to the smart pointer has been discussed here . It does not answer my question.*" Yes, it does. In the question, it says, "Now I know, that in such cases I should use a standard pointer." That's your answer. – Nicol Bolas Dec 29 '19 at 04:32
  • @NicolBolas , i tend to disagree . In the first place,the similar code in that question does not compile . – warrior_monk Dec 29 '19 at 04:47
  • @warrior_monk: Whether the code compiles isn't particularly relevant. The main point is that you're both trying to do the same thing: use a smart pointer to manage the lifetime of an object whose lifetime is automatic and will already be handled by the compiler. – Nicol Bolas Dec 29 '19 at 05:38
  • @NicolBolas . Thanks , I now get what you are saying . New to C++ , will get there ! – warrior_monk Dec 29 '19 at 06:02

3 Answers3

3

As stated here:

The object is disposed of using a potentially user-supplied deleter by calling get_deleter()(ptr). The default deleter uses the delete operator, which destroys the object and deallocates the memory.

unique_ptr holds a pointer to dynamically allocated variables stored on the heap. When you initialized int h, you stored this variable on the stack. It's pretty clear you shouldn't use delete on anything not allocated dynamically using new, so you will have to do this instead:

int* h_ptr = new int (100);
unique_ptr<int> temp1 {h_ptr};
NaShBe
  • 306
  • 2
  • 8
2

As stated in one of the answers to the question you link:

A unique_ptr is the exclusive owner of the pointed-to object. When it goes out of scope, it will delete the object.

That is, the pointer you pass to std::unique_ptr will need to be owned completely by the resulting std::unique_ptr. This is because once std::unique_ptr has the pointer, it will manage the pointer and attempt to delete it once the std::unique_ptr goes out of scope.

However, complete ownership is not the case here. h is a local variable. It will get destroyed once h goes out of scope. But it will also get destroyed once temp1 goes out of scope. So two things will try to destroy it. This will almost certainly result in undefined behavior, which is probably what you're seeing here.

This is why you shouldn't pass the address of local variables to std::unique_ptr, but rather pass addresses that are allocated dynamically, such as through new or std::make_unique().

0

Why Smart pointers can not be declared the usual Pointer way

std::shared_ptr/std::uniqure_ptr implicitly hold ownership to an object, so they are responsible to delete that object and you are not allowed to delete an object using delete for which a smart pointer has the ownership. std::experimental::observer_ptr (TS v2) and std::weak_ptr don't hold ownership.

A raw pointer on the other side can be both owning and not owning, so you need to document if that pointer holds ownership and whether the one having that pointer is responsible to call delete on it or not.

So what you do with unique_ptr<int> temp1 {&h}; is the same as with a raw pointer for which you documented that is an owning raw pointer, and on which you call delete.

int h {100};
int * temp1 = &h; // none owning pointer

// … some code here …

delete temp1; // calling delete on temp1 is not valid and would result in the same problem as with your unique_ptr example.

And whether you can transfer ownership of an object or not depends on the Storage duration

h falls in the group automatic:

automatic storage duration. The storage for the object is allocated at the beginning of the enclosing code block and deallocated at the end. All local objects have this storage duration, except those declared static, extern or thread_local.

And as of that, the ownership cannot be transferred as it is exclusively owned by the enclosing code block.

Ownership can only be transferred for objects with dynamic storage duration:

dynamic storage duration. The storage for the object is allocated and deallocated per request by using dynamic memory allocation functions. See new-expression for details on initialization of objects with this storage duration.

(automatic is what often is referred to as allocated on stack, and dynamic is what often is referred to as allocated on heap.)

t.niese
  • 39,256
  • 9
  • 74
  • 101