Reputation: 53
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?
Upvotes: 5
Views: 5820
Reputation: 217145
An alternative design would be
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;
}
Upvotes: 2
Reputation: 302817
createList()
returns a std::unique_ptr<Node>
. The constructor you're trying to use takes a Node*
as the first argument:
unique_ptr( pointer p, /* see below */ d1 ); (3)
unique_ptr( pointer p, /* see below */ d2 ); (4)
Hence the error.
If you want to keep the custom deleter local to main()
, you'll have to just pull the pointer out of createList
:
std::unique_ptr<Node, decltype(del1)> head(
createList().release(), // NB release(), not get()!
del1);
or change createList()
itself to return a std::unique_ptr<Node, decltype(del1)>
.
Upvotes: 2
Reputation: 72271
The two-argument constructor for unique_ptr
takes a raw pointer and a deleter, not a smart pointer and a deleter.
To make your example safe, createList
should probably return a unique_ptr
that would delete all the nodes in the first place.
Upvotes: 1
Reputation: 50540
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.
Upvotes: 5