Reputation: 509
I have a class containing such a structure:
class Store {
private:
struct pointNode {
T data;
std::unique_ptr<pointNode> next;
pointNode():data(std::move(T{})),next(std::move(std::unique_ptr<pointNode>{})){}
pointNode(T n_data, std::unique_ptr<pointNode> ptr) : data(std::move(n_data)), next(std::move(ptr)) {}
};
std::unique_ptr<pointNode> head;
public:
decltype(auto) Begin() ;
};
I need to create a Begin function that will get a pointer to head. I wrote something like this:
template<typename T>
decltype(auto) Stack<T>::Begin()
{
std::shared_ptr<pointNode> sh_ptr=std::make_shared<pointNode>(head);
return std::move(sh_ptr);
}
That is, create a shared_ptr and return it from the function, then go through the list. But:
std::shared_ptr<pointNode> sh_ptr=std::make_shared<pointNode>(head);
returns error C2664
Error C2664 "Stack<int>::pointNode::pointNode(Stack<int>::pointNode &&)":
argument 1 cannot be converted from "std::unique_ptr<Stack<int>::pointNode,std::default_delete<Stack<int>::pointNode>>"
in "const Stack<int>::pointNode &"
I tried to remove decltype (auto), but everything is the same .Maybe someone understands what I'm doing wrong .I would be happy to help, thank you
Upvotes: 0
Views: 255
Reputation: 117188
unique_ptr
s claim unique ownership. The clean way to transfer ownership to a shared_ptr
would be to move it. So if you have
std::unique_ptr<pointNode> head;
then
std::shared_ptr<pointNode> sh_ptr( std::move(head) );
This is however a design flaw.
You do not want to transfer ownership of the container's elements. Here you actually want to share the raw pointer with the iterator. Any iterator that you have should be able to use that raw pointer - but not destroy the element it points at.
The first draft of a simple forward list type of container would be something like the below - and nowhere should a unique_ptr
or shared_ptr
be used:
template<class T>
class Store {
private:
struct Node {
T data;
Node* next;
};
Node* head = nullptr;
public:
struct iterator {
iterator(Node* x = nullptr) : current(x) {}
T& operator*() { return current->data; }
T* operator->() { return ¤t->data; }
iterator& operator++() { current = current->next; return *this; }
bool operator!=(const iterator& rhs) const {
return current != rhs.current;
}
private:
Node* current;
};
~Store() {
Node* next;
while(head) {
next = head->next;
delete head;
head = next;
}
}
iterator begin() { return head; }
iterator end() { return nullptr; }
};
Upvotes: 1
Reputation: 29955
unique_ptr
cannot share the data with shared_ptr
. That's the point of a unique pointer. But if you want to transfer the ownership, you can do it like so:
#include <string>
#include <memory>
int main()
{
std::unique_ptr<std::string> up( new std::string("Hello, World!\n") );
// up owns the object
// Transfer ownership
std::shared_ptr<std::string> sp( up.release() );
// sp owns the object, up is empty.
}
Having said that, returning a shared_ptr
from the begin()
function is likely not what you want. I would guess that you want to return a reference or an iterator from that function. Here's how you can return a reference:
template<typename T>
pointNode& Stack<T>::begin()
{
return *head;
}
Note that, for this to work like STL iterators, you need to create a new iterator type. begin
returning a refence to a private node class is not a great interface and leaks implementation details.
Upvotes: 1