How to use unique_ptr as children in a tree - c++

I'm trying to make a tree with unique_ptr as children. This is the class for the moment :
class Part
{
public:
vector<Part>& getChildren() const {
return *m_children;
}
void attachChild(const unique_ptr<Part>& child) {
m_children.push_back(std::move(child));
}
vector<Part>& getAtoms() const {
vector<Part> atoms;
for (const auto& child : m_children) {
if (child->hasChildren()) {
vector<Part> childChildren = child->getAtoms();
atoms.insert(atoms.end(), childChildren.begin(), childChildren.end());
} else {
atoms.push_back(child);
}
}
return atoms;
}
vector<Part>& getAbsoluteAtoms() const {
vector<Part> atoms;
for (auto child : m_children) { // Not const because I modify the child
if (child->hasChildren()) {
vector<Part> childChildren = child->getAbsoluteAtoms();
atoms.insert(atoms.end(), childChildren.begin(), childChildren.end());
} else {
child.setPosition(child->getPosition() + m_position);
atoms.push_back(child);
}
}
return atoms;
}
private:
vector<unique_ptr<Part>> m_children;
};
I have a lot of errors, because of the pointers, like this one :
D:\Programmes\Qt\Tools\mingw530_32\i686-w64-mingw32\include\c++\bits\stl_construct.h:75: error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Part; _Dp = std::default_delete<Part>]'
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
^
Without them, everything works well but as a child can get really huge, I need them. Can you tell me why my code isn't correct?

With all due respect, I think you need to work on the basics of C++. For me it has been impossible to deduce what you want to achieve with this code. Maybe I could help you pointing out some mistakes, as I believe that should be your first step.
Bad use of std::move
void attachChild(const unique_ptr<Part>& child) {
m_children.push_back(std::move(child));
}
Why would you want to move a const&? And if it weren't a constant reference, do you think it would be worth moving it? And why is this a unique_ptr? m_children holds elements of type unique_ptr, and you want to fill that vector with the addChild method? Can we copy unique_ptr? They wouldn't be unique anymore. All of this is very strange. Impossible to understand what your intentions are.
Return type
vector<Part>& getAtoms() const { vector<Part> atoms; /* fill atoms */ return atoms; }
Are you sure you want to return a reference to a variable which gets destructed at the end of the getAtoms() function? The returntype should be
vector<Part>
Same here:
vector<Part>& getAbsoluteAtoms() const { ... }
vector<unique_ptr<Part>> m_children needed?
vector<unique_ptr<Part>> m_children;
I really wonder why you need to store a vector of unique_ptr in a class attribute. I'm sure you'll have your reasons. But before continuing, I'd revisit the basics of C++ (copy, reference, pointer, moving semantics, ...).

The error you mentioned tells you that you use the deleted copy constructor of unique_ptr. The reason why it is deleted, is that as the name implies there must always be just one unique_ptr that owns an allocated object.
One use of this copy constructor is in the default generated copy constructor of your Part class, which is used for example whenever you insert a Part into a vector<Part>. Another use is in the for (auto child : m_children) loops.
std::unique_ptr can only be moved, that means the source does not refer to the allocated object after the move to a new unique_ptr. Since the purpose of unique_ptr is to ensure that the owned object is deleted properly in all cases and never deleted twice, it makes sense that it cannot be blindly copied.
By using std::unique_ptr, you express that the parent "owns" the children, i.e. by copying the parent, you copy the children, by deleting the parent you delete the children.
This works nicely for trees, because every node has at most one parent, and you can probably take care of the roots.
If Part was representing a directed acyclic graph, you could use shared_ptr.
This is how I would write Part with hierarchical ownership:
#include <vector>
#include <memory>
class Part
{
public:
// or whatever constructor is useful
Part() = default;
~Part() = default;
// copy constructor needed because we cannot copy unique_ptr
Part(const Part &other) {
// cannot use just auto here, as that would try to copy the unique_ptrs
for(const auto &child_ptr : other.m_children) {
// we recursively copy all children
m_children.emplace_back(std::make_unique<Part>(*child_ptr));
}
}
// move constructor does what we expect
Part(Part && other) = default;
// since we need an explicit copy constructor it is
// good practice to mention also the assignment operators
// see also the "rule of five"
// copy assignment should be similar to the copy constructor, but first clear the children
Part &operator=(const Part &other) {
m_children.clear();
for(const auto &child_ptr : other.m_children) {
// we recursively copy all children
m_children.emplace_back(std::make_unique<Part>(*child_ptr));
}
return *this;
}
// moving should work as expected, we get all the children of other
Part &operator=(Part &&other) = default;
const std::vector<std::unique_ptr<Part>>& getChildren() const {
return m_children;
}
// we take a unique_ptr by value because it (the pointer) is small
void attachChild(std::unique_ptr<Part> child) {
m_children.push_back(std::move(child));
}
bool hasChildren() const {
return !m_children.empty();
}
private:
std::vector<std::unique_ptr<Part>> m_children;
};
// note how we return the vector by value,
// to avoid passing a stale reference
// the user will get a completely new vector
std::vector<Part> makeLotsOfParts(const Part &part) {
std::vector<Part> parts;
for(int i = 0; i < 10; ++i) {
// now we can copy parts!
parts.push_back(part);
}
// here the compiler will either apply the return value optimization
// or move the vector cheaply into the return value
return parts;
}
std::unique_ptr<Part> assemblePart() {
std::unique_ptr<Part> parent = std::make_unique<Part>();
std::unique_ptr<Part> child1 = std::make_unique<Part>();
// we do not need child1 any more, so we move from it
parent->attachChild(std::move(child1));
std::unique_ptr<Part> child2 = std::make_unique<Part>();
parent->attachChild(std::move(child2));
// again we can rely on RVO or move
return parent;
}

Related

How to free memory with move constructor

I am trying to create my own vector and here is a minimal example to introduce the problem I have:
class DemoVector {
public:
DemoVector() : capacity_(1), size_(0) {
data_ = new int[1];
}
DemoVector(DemoVector&& rhs) {
data_ = std::move(rhs.data_);
size_ = rhs.size_;
capacity_ = rhs.capacity_;
}
~DemoVector() {
delete[] data_;
}
void PushBack(const int &v) {
// doesn't matter
}
private:
int *data_;
size_t capacity_;
size_t size_;
};
Test:
TEST_CASE("Test") {
DemoVector b;
b.PushBack(1);
DemoVector c(std::move(b));
}
I have a problem here and I understand why. I have two objects which points on the same memory. Second destructor tries to free memory, which have already been freed by first destructor.
But I don't know how to fix it.
Thank you for your help.
std::move(rhs.data_) doesn't actually move anything. std::move is nothing more than a named cast. It produces an rvalue reference that allows move semantics to occur. But for primitive types, it's just a copy operation. The pointer is being copied, and so you end up with two pointers that contain the same address. Since you don't want the source object to still be pointing at the the same buffer, simply modify it. That's why move-semantics is build around non-const references.
Move constructors are commonplace now, so there's a standard utility (C++14) to help write them in a way that makes code behave more as you'd expect. It's std::exchange. You can simply write
DemoVector(DemoVector&& rhs)
: data_(std::exchange(rhs.data_, nullptr))
, size_(std::exchange(rhs.size_ , 0))
, capacity_(std::exchange(rhs.capacity_ , 0))
{}
And all the values get adjusted properly. std::exchange modifies its first argument to hold the value of the second argument. And finally, it return the old value of the first argument. Very handy to shift values around in one-liner initializations.
Because std::move is basically just a cast that doesn't actually move anything! You need to update the values in the other object yourself:
DemoVector(DemoVector&& rhs) {
data_ = rhs.data_;
size_ = rhs.size_;
capacity_ = rhs.capacity_;
rhs.data_ = nullptr;
rhs.size_ = 0;
rhs.capacity = 0;
}
Or alternatively to make use of the existing constructor:
DemoVector(DemoVector&& rhs): DemoVector() {
// Or write your own swap function to reuse this elsewhere
std::swap(data_, rhs.data_);
std::swap(size_, rhs.size_);
std::swap(capacity_, rhs.capacity_);
}
It's up to you how you want users of your class to handle moved-from objects. In the second case, and possibly also the first depending on how the rest of your class works, rhs (b in your test case) will be an empty vector.

C++assingment operator using destructor and copying constructor

I was working on a class with multiple dynamic fields and I was looking for quick way of coding assignment operator.
So let's say I have some basic class Cla, which stores dynamic array of integers (arr) and the size of said array (n).
I've coded this:
Cla::Cla(int* arr, int n) : n(n)
{
this->arr = new int[n];
//allocation error handling
while (--n >= 0)
this->arr[n] = arr[n];
}
Cla::~Cla()
{
delete[] arr;
}
Cla::Cla(const Cla& copy) : Cla(copy.arr, copy.n){}
Cla& Cla::operator= (const Cla& asg)
{
this->~Cla();
*this = asg;
return *this;
}
All of it works properly, except for operator=. The idea was that I'll just destroy my object and then create it again with copying constructor (for the sake of simplicity of the example I don't consider the situation where both objects have the same size and there is no need for deallocation and new allocation). It compiles, but it gives me some nasty errors when executed.
Can you give me some advice on how to correct this code? Is this even possible for it to work this way?
(I know how to write an assingment operator, I'm just asking whether it is possible to do it using destructor and copying constructor. I couldn't find anything like that on the internet.)
Your operator= has undefined behavior. First, you cannot manually call a destructor on an object that was not allocated with placement-new. Second, once an object is destroyed, it cannot be used anymore, which means *this = asg is accessing invalid memory once this->~Cla() has been called, as this is no longer pointing at a valid object. Third, your operator= is running an endless recursion loop, calling itself over and over until the call stack blows up (if you are lucky).
Since you want to use your copy constructor, your operator= would be better served by using the copy-swap idiom instead. Construct a local object to make use of your copy constructor, and then swap the contents of that object with this so that this takes ownership of the copied data and the local object frees the old data when it goes out of scope, eg:
Cla& Cla::operator= (const Cla& asg)
{
if (&asg != this)
{
Cla temp(asg);
std::swap(arr, temp.arr);
std::swap(n, temp.n);
}
return *this;
}
Alternatively:
void Cla::swap(Cla &other)
{
std::swap(arr, other.arr);
std::swap(n, other.n);
}
Cla& Cla::operator= (const Cla& asg)
{
if (&asg != this) {
Cla(asg).swap(*this);
}
return *this;
}
That being said, the fact that your copy constructor is delegating to your converting constructor means that you are using C++11 or later, in which case you should also implement move semantics into your class, not just copy semantics, eg:
Cla::Cla() : arr(nullptr), n(0)
{
}
Cla::Cla(int* arr, int n) : arr(new int[n]), n(n)
{
while (--n >= 0)
this->arr[n] = arr[n];
}
Cla::Cla(Cla &&c) : arr(nullptr), n(0)
{
c.swap(*this);
}
Cla::Cla(const Cla& c) : Cla(c.arr, c.n)
{
}
Cla::~Cla()
{
delete[] arr;
}
void Cla::swap(Cla &other)
{
std::swap(arr, other.arr);
std::swap(n, other.n);
}
Cla& Cla::operator= (Cla asg)
{
asg.swap(*this);
return *this;
}
By passing the asg parameter by value, operator= can decide whether to use copy semantics or move semantics at the call site based on whether an lvalue or rvalue is being passed to it. The compiler will pick the appropriate constructor to construct the asg parameter with, and then this can take ownership of the resulting data.

Can I get away with putting auto_ptr in a STL container?

I am inheriting an interface, and implementing a virtual function that is supposed to do some work on a list of dynamically allocated objects. The first step is to remove duplicates from the list based on some custom equivalence criteria:
class Foo { /* ... */ };
struct FooLess
{
bool operator()(const Foo *lhs, const Foo *rhs);
}
struct FooEqual
{
bool operator()(const Foo *lhs, const Foo *rhs);
}
void doStuff(std::list<Foo*> &foos)
{
// use the sort + unique idiom to find and erase duplicates
FooLess less;
FooEqual equal;
foos.sort( foos.begin(), foos.end(), less );
foos.erase(
std::unique( foos.begin(), foos.end(), equal ),
foos.end() ); // memory leak!
}
The problem is that using sort + unique doesn't clean up the memory, and the elements to be erased have unspecified values after unique, so I cannot perform the cleanup myself before eraseing. I was considering something like this:
void doStuff(std::list<Foo*> &foos)
{
// make a temporary copy of the input as a list of auto_ptr's
std::list<auto_ptr<Foo>> auto_foos;
for (std::list<Foo>::iterator it = foos.begin(); it != foos.end(); ++it)
auto_foos.push_back(auto_ptr<Foo>(*it));
foos.clear();
FooLess less; // would need to change implementation to work on auto_ptr<Foo>
FooEqual equal; // likewise
auto_foos.sort( auto_foos.begin(), auto_foos.end(), less );
auto_foos.erase(
std::unique( auto_foos.begin(), auto_foos.end(), equal ),
auto_foos.end() ); // okay now, duplicates deallocated
// transfer ownership of the remaining objects back
for (std::list<auto_ptr<Foo>>::iterator it = auto_foos.begin();
it != auto_foos.end(); ++it)
{ foos.push_back(it->get()); it->release(); }
}
Will this be okay, or am I missing something?
I am not able to use C++11 (Boost might be possible) or change the function signature to accept a list of straightforward Foos.
To put an object into a standard container the object needs value semantics (the standard says "copy assignable" and "copy constructable"). Among other things, that means the copy constructor and assignment operator needs to create a copy of an object (leaving the original intact)
The auto_ptr copy constructor does not do that. Instead, the copy constructor and assignment operator transfer ownership of the pointer.
As a consequence, it is not possible for a standard container to contain an auto_ptr.
A lot of implementations (as in compiler and standard library) have the standard containers and/or auto_ptr coded so attempting to have a container of auto_ptr's will trigger a compiler error. Unfortunately, not all implementations do that.
There are generally the following methods you can use in C++98:
Define some pointer that will do what std::auto_ptr can't do. There was an old version of that thing, which contained an additional field of type bool that marked ownership. It was marked mutable, so it could be modified also in the object being read from when copying. The object was deleted at the end only if owned was true. Something like:
==
template <class T> class owning_ptr
{
T* ptr;
mutable bool owns;
public:
void operator =(T* src) { ptr = src; owns = true; }
owning_ptr(const owning_ptr& other)
{
// copy the pointer, but STEAL ownership!
ptr = other.ptr; owns = other.owns; other.owns = false;
}
T* release() { owns = false; return ptr; }
~owning_ptr() { if ( owns ) delete ptr; }
/* ... some lacking stuff ..*/
};
You may try out boost::shared_ptr
Instead of std::unique, you may try to do std::adjacent_find in a loop. Then you'll just find all elements that are "the same" as by your equal. If there's more than one element, you will erase them in place (you are allowed to do it because it's a list, so iterators remain valid).

Deallocating memory from a private class variable

#include <stdio.h>
#include <iostream>
#include <string>
using namespace std;
class myClass{
public:
int *num1;
myClass();
};
myClass::myClass(){
num1 = new int[1];
num1[0] = 10;
}
int main()
{
myClass *myclass;
myclass = new myClass[10];
cout << myclass[0].num1[0] << endl;
delete &myclass[0];
cout << myclass[0].num1[0] << endl;
}
I want to delete the first instance of myclass (myclass[0]).
This code does not run correctly, it fails during the delete part. There is probably something I am missing.
What did I do wrong?
You cannot delete just a portion of an array created with new. new allocates a block of memory which can only be deleteed all together.
If you want an object to free its own internal data you'll have to arrange for the class, which should encapsulate and hide its own internal resources, to do that itself.
If you want a smaller block of memory holding the array you allocated, then you must allocate a smaller block and move the contents that you wish to keep into the new block, and then delete the entire old block:
int *arr = new int[10];
int *tmp = new int[9];
std::copy(arr+1, arr+10, tmp);
delete [] arr;
arr = tmp;
You need to design your class to manage its own resources, and to handle copying or moving. Your current myClass allocates an array but relies on other code to handle cleaning up. This is not a good way to go about doing this, because often no other code is in a good position to do the correct thing, and even when you could you'll very frequently make mistakes.
Since you're allocating in the constructor you need a destructor that handles deallocation. And then since you implement one of three special operations (copy-ctor, copy-assignment, destructor) you need to consider implementing them all. (This is called 'The Rule of Three'. In C++11 it becomes 'The Rule of Five' with the addition of move-ctors and move assignment.)
class myClass {
public:
myClass();
// destructor to handle destroying internal resources correctly
~myClass();
// copy constructor and copy assignment operator, to handle copying correctly
myClass(myClass const &rhs);
myClass &operator=(myClass const &rhs);
// move constructor and move assignment operator, to handle moves correctly (C++11)
myClass(myClass && rhs);
myClass &operator= (myClass &&rhs);
private:
int *num1; // private so external code can't screw it up
public:
// limited access to num1
int size() const { if (num1) return 1; else return 0; }
int &operator[] (size_t i) { return num1[i]; }
};
You can implement the constructor just as you did, or you could use the initializer list and C++11 uniform initialization:
myClass::myClass() : num1(new int[1]{10}) {}
Now, the destructor you want depends on the semantics you want the class to have, and the particular invariants you want to maintain. 'value' semantics are the norm in C++ (if you're familiar with Java or C# those languages encourage or require 'reference' semantics for user defined types). Here's a destructor you might use if you want value semantics, and if you maintain an invariant that num1 always owns memory or is null.
myClass::~myClass() { delete num1; }
Copying and moving can be handled in different ways. If you want to disallow them entirely you can say (in C++11):
myClass::myClass(myClass const &rhs) = delete;
myClass &myClass::operator=(myClass const &rhs) = delete;
myClass::myClass(myClass && rhs) = delete;
myClass &myClass::operator= (myClass &&rhs) = delete;
Or if you want to allow copying and or moving (and maintain value semantics and the invariant mentioned above) then you can implement either or both of these pairs of functions:
myClass::myClass(myClass const &rhs) : num1( rhs.size() ? new int[1]{rhs[0]} : nullptr) {}
myClass &myClass::operator=(myClass const &rhs) {
if (num1)
num1[0] = rhs[0];
}
myClass::myClass(myClass && rhs) : num1(rhs.num1) { rhs.num1 = nullptr; } // remember to maintain the invariant that num1 owns the thing it points at, and since raw pointers don't handle shared ownership only one thing can own the int, and therefore only one myClass may point at it. rhs.num1 must be made to point at something else...
myClass &myClass::operator= (myClass &&rhs) { std::swap(num1, rhs.num1); } // steal rhs.num1 and leave it to rhs to destroy our own num1 if necessary. We could also destroy it ourselves if we wanted to.
With this implementation you can now treat a myClass object the same as you would an int or any other 'value' type. You no longer need to worry about managing its internal resources; it will take care of them itself.
int main() {
std::vector<myClass> myclassvec(10);
cout << myclassvec[0][0] << '\n';
myclassvec.erase(myclassvec.begin()); // erase the first element
cout << myclassvec[0][0] << '\n'; // access the new first element (previously the second element);
}
Create a function inside of your class the handles the deletion of its private members, maybe called FreeMem(int index)
void myClass::FreeMem()
{
delete [] num1
}
But honestly, freeing memory of an object without the use of a destructor in this sort of a program is hazardous and downright bad practice. I would recommend freeing the memory in your destructor, so when the object terminates it frees the memory,
myClass::~myClass()
{
delete [] num1;
}
Another thing to note on, if you're only creating one value in your dynamic variable, it would be easier to write it as:
int * pnum = new int;
//or in your class..
pnum = new int;
among other things, you have a lot of flaws in your program. I would recommend re-reading up on classes again.

Move Constructors and Static Arrays

I've been exploring the possibilities of Move Constructors in C++, and I was wondering what are some ways of taking advantage of this feature in an example such as below. Consider this code:
template<unsigned int N>
class Foo {
public:
Foo() {
for (int i = 0; i < N; ++i) _nums[i] = 0;
}
Foo(const Foo<N>& other) {
for (int i = 0; i < N; ++i) _nums[i] = other._nums[i];
}
Foo(Foo<N>&& other) {
// ??? How can we take advantage of move constructors here?
}
// ... other methods and members
virtual ~Foo() { /* no action required */ }
private:
int _nums[N];
};
Foo<5> bar() {
Foo<5> result;
// Do stuff with 'result'
return result;
}
int main() {
Foo<5> foo(bar());
// ...
return 0;
}
In this above example, if we trace the program (with MSVC++ 2011), we see that Foo<N>::Foo(Foo<N>&&) is called when constructing foo, which is the desired behaviour. However, if we didn't have Foo<N>::Foo(Foo<N>&&), Foo<N>::Foo(const Foo<N>&) would be called instead, which would do a redundant copy operation.
My question is, as noted in the code, with this specific example which is using a statically-allocated simple array, is there any way to utilize the move constructor to avoid this redundant copy?
First off, there's a general sort of advice that says you shouldn't write any copy/move constructor, assignment operator or destructor at all if you can help it, and rather compose your class of high-quality components which in turn provide these, allowing the default-generated functions to Do The Right Thing. (The reverse implication is that if you do have to write any one of those, you probably have to write all of them.)
So the question boils down to "which single-responsibility component class can take advantage of move semantics?" The general answer is: Anything that manages a resource. The point is that the move constructor/assigner will just reseat the resource to the new object and invalidate the old one, thus avoiding the (presumed expensive or impossible) new allocation and deep copying of the resource.
The prime example is anything that manages dynamic memory, where the move operation simply copies the pointer and sets the old object's pointer to zero (so the old object's destructor does nothing). Here's a naive example:
class MySpace
{
void * addr;
std::size_t len;
public:
explicit MySpace(std::size_t n) : addr(::operator new(n)), len(n) { }
~MySpace() { ::operator delete(addr); }
MySpace(const MySpace & rhs) : addr(::operator new(rhs.len)), len(rhs.len)
{ /* copy memory */ }
MySpace(MySpace && rhs) : addr(rhs.addr), len(rhs.len)
{ rhs.len = 0; rhs.addr = 0; }
// ditto for assignment
};
The key is that any copy/move constructor will do a full copying of the member variables; it is only when those variables are themselves handles or pointers to resources that you can avoid copying the resource, because of the agreement that a moved object is no longer considered valid and that you're free to steal from it. If there's nothing to steal, then there's no benefit in moving.
In this case it's not useful because int has no move-constructors.
However, it could be useful if those were strings instead, for example:
template<unsigned int N>
class Foo {
public:
// [snip]
Foo(Foo<N>&& other) {
// move each element from other._nums to _nums
std::move(std::begin(other._nums), std::end(other._nums), &_nums[0]);
}
// [snip]
private:
std::string _nums[N];
};
Now you avoid copying strings where a move will do. I'm not sure if a conforming C++11 compiler will generate equivalent code if you omit all the copy-/move-constructors completely, sorry.
(In other words, I'm not sure if std::move is specially defined to do an element-wise move for arrays.)
For the class template you wrote, there's no advantage to take in a move constructor.
There would be an advantage if the member array was allocated dynamically. But with a plain array as a member, there's nothing to optimize, you can only copy the values. There's no way to move them.
Usually, move-semantic is implemented when your class manages resource. Since in your case, the class doesn't manages resource, the move-semantic would be more like copy-semantic, as there is nothing to be moved.
To better understand when move-semantic becomes necessary, consider making _nums a pointer, instead of an array:
template<unsigned int N>
class Foo {
public:
Foo()
{
_nums = new int[N](); //allocate and zeo-initialized
}
Foo(const Foo<N>& other)
{
_nums = new int[N];
for (int i = 0; i < N; ++i) _nums[i] = other._nums[i];
}
Foo(Foo<N>&& other)
{
_nums = other._nums; //move the resource
other._nums=0; //make it null
}
Foo<N> operator=(const Foo<N> & other); //implement it!
virtual ~Foo() { delete [] _nums; }
private:
int *_nums;
};