Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11 using unique_ptr with custom deleter

I'm trying to learn C++11 unique_ptr usage by doing a simple linked list program. For the life of me I can't figure out why I'm getting a compile error when using a custom deleter.

#include <cstdio>
#include <limits>
#include <memory>
#include <cstdlib>
#include <iostream>

using namespace std;

struct node {
    int value;
    struct node* next;
};

typedef struct node Node;

std::unique_ptr<Node> createList()
{

    std::unique_ptr<Node> head(new Node);
    Node* temp=head.get();
    temp->value=0;
    for(int i=1;i<8;i++) {
        if(temp->next==nullptr) {
            temp->next=new Node();
            temp=temp->next;
            temp->value=i;
            temp->next=nullptr;
        }
    //temp=temp->next;
    }
    return head;
}

int main()
{
    auto del1 = [](Node* p) { while(p) {std::cout << "Deleting value is : " << p->value;struct node* n=p->next;delete p; p=n;} return; };

    std::unique_ptr< Node, decltype(del1) > head(std::move(createList()),del1);
}

And here is the compilation error

sh-4.3$ g++ -std=c++11 -o main *.cpp                                                                                                                   
main.cpp: In function 'int main()':                                                                                                                    
main.cpp:38:82: error: no matching function for call to 'std::unique_ptr<node, main()::<lambda(Node*)> >::unique_ptr(std::remove_reference<std::unique_
ptr<node> >::type, main()::<lambda(Node*)>&)'                                                                                                          
         std::unique_ptr< Node, decltype(del1) > head(std::move(createList()),del1);                                                                   
                                                                                  ^                                                                    
In file included from /usr/include/c++/5.3.1/memory:81:0,                                                                                              
                 from main.cpp:3:                                                                                                                      
/usr/include/c++/5.3.1/bits/unique_ptr.h:228:2: note: candidate: template<class _Up, class> std::unique_ptr<_Tp, _Dp>::unique_ptr(std::auto_ptr<_Up>&&)
  unique_ptr(auto_ptr<_Up>&& __u) noexcept;                                                                                                            
  ^                                                                                                                                                    
/usr/include/c++/5.3.1/bits/unique_ptr.h:228:2: note:   template argument deduction/substitution failed:                                               
main.cpp:38:82: note:   'std::remove_reference<std::unique_ptr<node> >::type {aka std::unique_ptr<node>}' is not derived from 'std::auto_ptr<_Up>'     
         std::unique_ptr< Node, decltype(del1) > head(std::move(createList()),del1);                                                                   
                                                                                  ^                                                                    
In file included from /usr/include/c++/5.3.1/memory:81:0,                                                                                              
                 from main.cpp:3:                                                                                                                      
/usr/include/c++/5.3.1/bits/unique_ptr.h:220:2: note: candidate: template<class _Up, class _Ep, class> std::unique_ptr<_Tp, _Dp>::unique_ptr(std::uniqu
e_ptr<_Up, _Ep>&&)                                                                                                                                     
  unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept                                                                                                      
  ^                                                                                                                                                    
/usr/include/c++/5.3.1/bits/unique_ptr.h:220:2: note:   template argument deduction/substitution failed:                                               
main.cpp:38:82: note:   candidate expects 1 argument, 2 provided                                                                                       
         std::unique_ptr< Node, decltype(del1) > head(std::move(createList()),del1);    

Any ideas?

like image 404
ashwinaj Avatar asked Jul 20 '16 16:07

ashwinaj


People also ask

Can you delete a unique_ptr?

An explicit delete for a unique_ptr would be reset() . But do remember that unique_ptr are there so that you don't have to manage directly the memory they hold. That is, you should know that a unique_ptr will safely delete its underlying raw pointer once it goes out of scope.

Can you pass a unique_ptr?

Because the unique pointer does not have a copy constructor. Hence you cannot pass it by value, because passing by value requires making a copy. Actually that is nearly the sole and whole point of a unique_ptr .

Why would you choose shared_ptr instead of unique_ptr?

Use unique_ptr when you want to have single ownership(Exclusive) of the resource. Only one unique_ptr can point to one resource. Since there can be one unique_ptr for single resource its not possible to copy one unique_ptr to another. A shared_ptr is a container for raw pointers.

What happens when unique_ptr goes out of scope?

std::unique_ptr is a smart pointer that owns and manages another object through a pointer and disposes of that object when the unique_ptr goes out of scope. The object is disposed of, using the associated deleter when either of the following happens: the managing unique_ptr object is destroyed.


1 Answers

You should return the correct type from createList:

#include <cstdio>
#include <limits>
#include <memory>
#include <cstdlib>
#include <iostream>

using namespace std;

struct node {
    int value;
    struct node* next;
};

typedef struct node Node;

auto createList()
{
    auto del1 = [](Node* p) { while(p) {std::cout << "Deleting value is : " << p->value;struct node* n=p->next;delete p; p=n;} return; };
    std::unique_ptr< Node, decltype(del1) > head(new Node,del1);

    Node* temp=head.get();
    temp->value=0;
    for(int i=1;i<8;i++) {
        if(temp->next==nullptr) {
            temp->next=new Node();
            temp=temp->next;
            temp->value=i;
            temp->next=nullptr;
        }
    //temp=temp->next;
    }
    return head;
}

int main()
{
    auto node = createList();
 }

Otherwise, in the code shown in the question, you should take ownership of the internal data and move them, being the pointers of different types:

int main()
{
    auto del1 = [](Node* p) { while(p) {std::cout << "Deleting value is : " << p->value;struct node* n=p->next;delete p; p=n;} return; };

    std::unique_ptr< Node, decltype(del1) > head(createList().release(),del1);
}

Note the call to .release().
See here for further details.

like image 192
skypjack Avatar answered Oct 21 '22 07:10

skypjack