【问题标题】:C++11 using unique_ptr with custom deleterC++11 使用带有自定义删除器的 unique_ptr
【发布时间】:2016-11-23 23:34:44
【问题描述】:

我正在尝试通过做一个简单的链表程序来学习 C++11 unique_ptr 的用法。在我的一生中,我无法弄清楚为什么在使用自定义删除器时会出现编译错误。

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

有什么想法吗?

【问题讨论】:

  • head(std::move(createList()), ...,你为什么要移动右值?
  • 我只是在尝试 C++11 中所有花哨的新事物,std::move 可能是隐式的(因为 createList 返回一个右值)并且不是必需的。
  • createList的返回类型不包含你的删除器,所以是不同的类型

标签: c++ c++11 std smart-pointers


【解决方案1】:

你应该从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

【讨论】:

  • 谢谢。我尝试了你的第二个选项,我得到了这个:参数 1 从“std::default_delete”到“const main()::__lambda0&” 没有已知的转换
  • Skypjack,我在原始问题中添加了编译错误。
  • @ashwinaj 请参阅上一条评论中的链接。那是你做的吗?您确实不应该以这种方式编辑问题。
【解决方案2】:

unique_ptr 的双参数构造函数采用原始指针和删除器,而不是智能指针和删除器。

为了使您的示例安全,createList 可能应该返回一个 unique_ptr,这将首先删除所有节点。

【讨论】:

  • 老实说,最安全的可能是在Node 中有一个析构函数
【解决方案3】:

createList() 返回一个std::unique_ptr&lt;Node&gt;。您尝试使用的constructorNode* 作为第一个参数:

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

因此错误。

如果您想将自定义删除器保留在main() 的本地,您只需将指针拉出createList

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

或更改createList() 本身以返回std::unique_ptr&lt;Node, decltype(del1)&gt;

【讨论】:

  • 这与我在其他答案中所说的有什么不同?
  • @skypjack 我写这个答案时你没有发布选项,你也没有解释为什么 OP 的代码不起作用。
  • 有道理。我通过编辑添加了对release 的引用,但我没有注意到您同时回答了。对不起。
【解决方案4】:

另一种设计是

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

【讨论】:

  • @ashwinaj: 你不再需要自定义删除器了
猜你喜欢
  • 1970-01-01
  • 2012-04-11
  • 2015-08-15
  • 2019-01-16
  • 2016-03-31
  • 1970-01-01
  • 2013-03-30
  • 2015-09-11
  • 2019-12-11
相关资源
最近更新 更多