Use of deleted function unique_ptr::unique_ptr

I have the following header and class file in a project:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef PATTERN_HPP_
#define PATTERN_HPP_

#include <memory>
#include <list>
using namespace std;

namespace pub {
	class Pattern {
		private:
			unique_ptr<Pattern> left;
			list<Pattern> up;
		public:
			list<Pattern> validate();
	};
}

#endif 


1
2
3
4
5
6
7
8
9
#include "Pattern.hpp"

namespace pub {
	list<Pattern> Pattern::validate() {
		list<Pattern> validPatterns(up);

		return validPatterns;
	}
}


When I try to compile it, I get the error "Use of deleted function unique_ptr" etc etc etc. Having googled the error, I understand that it has something to do with unique pointers not being copyable, but only moveable, but I don't see why that applies in my case.

I have checked the constructor documentation for unique_ptr, so I am sure that I can define my left variable like that, as far as I understand, it will then be pointing to a nullptr. At any rate, that is one of many ways it is shown in that documentation.

So what am I doing wrong, and how do I fix this error?

And FYI, my class and header actually contains a lot more code, but this is the minimum I could boil it down to, and still get that error. It seems to be related to the validate function.
this line:
list<Pattern> validPatterns(up);attempts to copy-construct validPatterns from up, which isn't possible. You can see the error going away with list<Pattern> validPatterns(move(up)); (which probably won't make logical sense in the program, though)

Last edited on
Right, that makes perfect sense, since it's trying to copy all the fields of all elements in the list, and unique_ptr can't be copied. I don't know why I didn't think of that myself.

But what does move do then? Does it instead move all the fields or what? And if I use move, can I then afterwards iterate over the list up, or is that emptied and discarded after move?

Edit:
Okay, I tried that and it worked fine. Then I uncommented the remainder of the code in that function, and now I get that same error again, along with a new error "use of deleted function Pattern::Pattern(const Pattern&)" or something to that extent. So here is my function in its entirety.

1
2
3
4
5
6
7
8
9
10
11
12
13
#include "Pattern.hpp"

namespace pub {
	list<Pattern> Pattern::validate() {
		list<Pattern> validPatterns(move(up));

		for (Pattern ptrn : up) {
			validPatterns.splice(validPatterns.begin(), ptrn.validate());
		}

		return validPatterns;
	}
}


And that is all there is in that class. The header file remains unchanged. The error is on the for loop line, and it seems to me like it's trying to create a new Pattern with the default constructor, rather than iterating through the list, though I don't know why.
Last edited on
is that emptied and discarded after move?

it is typically emptied, but it's still a valid list.

The error is on the for loop line
for (Pattern ptrn : up) this requests a new Pattern object called ptrn to be copy-constructed from each element of the vector. A more common pattern is to use references: for (Pattern& ptrn : up) or for(Pattern&& ptrn: up).

note that since you moved the contents of up into validPatterns, the loop will execute zero iterations. Consider writing a function to clone those lists, if that's what is really needed.
Since the function is called recursively, moving the objects works just fine, since I need to assemble them into one big list, and it saves me memory, so I'll just iterate over validPatterns instead. But why two ampersands?

Edit: Actually, come to think of it, moving the up list, obviously means I will only get the expected result the first time I call validate(), since it will be empty after that. So I do need to look into cloning lists, as you mention.

Edit 2: Now I'm really glad you said that, because I've thought some more about it, and this actually means I can't use a unique_ptr, since I need both validPatterns and up to point to an object at the same time. One last question though. As it turns out I can only use a weak_ptr. But how do I access the object that it is pointing to? The documentation doesn't mention a get method, unlike for shared_ptr.
Last edited on
Now I'm really glad you said that, because I've thought some more about it, and this actually means I can't use a unique_ptr, since I need both validPatterns and up to point to an object at the same time.

It doesn't mean that. It means that if you use a unique_ptr you need to supply a copy constructor and copy assignment operator that make sense for your class. If that can't be done, then you need to either use a shared_ptr or some other smart pointer that supports the semantics you want to use.


As it turns out I can only use a weak_ptr. But how do I access the object that it is pointing to? The documentation doesn't mention a get method, unlike for shared_ptr.

You cannot use weak_ptrs without also using shared_ptr. In fact, the way you get at the object a weak_ptr is pointing to is by creating a shared_ptr via the lock method.
But doesn't a unique_ptr require a lock on the object, it's pointing at, thus meaning no other pointers can use it?
But doesn't a unique_ptr require a lock on the object, it's pointing at, thus meaning no other pointers can use it?


Smart pointers are about managing ownership. They're not about restricting access. You can have any number of raw pointers to an object that is owned by a unique_ptr.

You really haven't provided enough context about what you're doing to say what an appropriate approach is.
Sorry my bad, I was thinking of unique_ptrs instead of weak_ptrs there. One last question though, that I couldn't find an answer to on Google. Why do you use two ampersands in your example? Does that make it a reference to a reference to a Pattern, and why?

Edit: Okay, one last last question. As long as I don't use new and delete, C++ will take care of cleaning up memory for me, as far as I understand. And if I have a weak_ptr to an object that has no shared_ptrs, the object is automatically removed from memory when the scope ends, and the weak_ptr is reset automatically as well. But is the weak_ptr then also removed from memory, or will I need to do that explicitly?
Last edited on
Topic archived. No new replies allowed.