2016-07-20 1 views
4

Я пытаюсь изучить использование C++ 11 unique_ptr, выполнив простую связанную программу списка. Для жизни я не могу понять, почему я получаю ошибку компиляции при использовании пользовательского удаления.C++ 11 using unique_ptr с пользовательским 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); 
} 

А вот ошибка компиляции

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);  

Любые идеи?

+1

В 'голове (станд :: ход (createList()), ...', почему вы перемещаете RValue? – KABoissonneault

+0

Я просто попробовать все новые идеи в C++ 11, std :: move, вероятно, неявный (поскольку createList возвращает rvalue) и не требуется. – ashwinaj

+1

Возвратный тип 'createList' не включает ваш deleter, так что это другой тип – Galik

ответ

4

Вы должны вернуть правильный тип из 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(); 
} 

В противном случае в коде, показанном в этом вопросе, вы должны взять на себя ответственность внутренних данных и перемещать их, будучи указатели разных типов:

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); 
} 

Обратите внимание на звонок .release().
Для получения дополнительной информации см. here.

+0

Спасибо. Я попробовал ваш второй вариант, и я получаю это: никакого известного преобразования для аргумента 1 из 'std :: default_delete ' to 'const main() :: __ lambda0 &' – ashwinaj

+1

@ashwinaj [It works] (https://godbolt.org/ g/5pa5h3), что не так ? – skypjack

+0

Skypjack, я добавил ошибку компиляции в моем исходном вопросе. – ashwinaj

1

Конструктор с двумя аргументами для unique_ptr берет необработанный указатель и удаляющий элемент, а не умный указатель и дебетер.

Чтобы сделать ваш пример безопасным, createList должен, вероятно, вернуть unique_ptr, который удалит все узлы в первую очередь.

+0

Самый безопасный, вероятно, будет иметь деструктор в «Узде», если честно – KABoissonneault

2

createList() возвращает std::unique_ptr<Node>. constructor вы пытаетесь использовать берет Node* в качестве первого аргумента:

unique_ptr(pointer p, /* see below */ d1); (3)  
unique_ptr(pointer p, /* see below */ d2); (4)  

Следовательно, ошибка.

Если вы хотите сохранить пользовательский Deleter локального для main(), вам придется просто вытащить указатель из createList:

std::unique_ptr<Node, decltype(del1)> head(
    createList().release(), // NB release(), not get()! 
    del1); 

createList() или изменить себя, чтобы вернуть std::unique_ptr<Node, decltype(del1)>.

+0

Как это отличается от того, что я сказал в другом ответе? – skypjack

+0

@skypjack У вас не было варианта выпуска, когда я написал этот ответ, и у вас нет объяснений, почему код OP не работает. – Barry

+0

Это имеет смысл. Я добавил ссылку на 'release' с редактированием, но я не заметил, что вы ответили тем временем. Прости. – skypjack

2

Альтернативный дизайн будет

struct Node { 
    Node(int value) : value(value) {} 

    int value; 
    std::unique_ptr<Node> next; 
}; 

std::unique_ptr<Node> createList() 
{ 
    std::unique_ptr<Node> head = std::make_unique<Node>(0); 

    Node* node = head.get(); 
    for(int i = 1; i < 8; i++) { 
     node->next = std::make_unique<Node>(i); 
     node = node->next.get(); 
    } 
    return head; 
} 
+0

@ashwinaj: вам больше не нужен пользовательский деактивист – Roland