How to free memory with move constructor - c++

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.

Related

Why the copy and move constructors end up in the same amount of memcopies?

Thee problem here is to understand if the copy or move constructor was called when initializing a vector by a return object of a function.
Checking the mallocs with a profiler shows similar memcopies in both cases. Why?
We have a class of type "message". The class provides a function "data_copy" which returns the contents of the "message" as vector.
There are 2 options that I tried.
One is to use directly the copy constructor to initialize a new vector.
std::vector<uint8_t> vector1 ( message.data_copy() );
The second option was to try to avoid the extra copy and do
std::vector<uint8_t> vector1 ( std::move( message.data_copy() ) );
For reference I attach what data_copy() does.
std::vector<uint8_t> message::data_copy(void) const
{
std::vector<uint8_t> d(this->size());
copy_data_to_buffer(d.data());
return d;
}
void message::copy_data_to_buffer(uint8_t* buffer) const
{
DEBUG_LOG("copy_data_to_buffer");
for(const fragment* p = &head; p != nullptr; p = p->next)
{
memcpy(buffer, p->data[0], p->size[0]);
buffer += p->size[0];
if(p->size[1])
{
memcpy(buffer, p->data[1], p->size[1]);
buffer += p->size[1];
}
}
}
Finally, by using a profiler I compare the amount of malloc calls. While one would expect that the move constructor would avoid the extra memcopy in reality they are the same in both cases.
You are using the move constructor both times. The result of data_copy is a temporary. Then you construct the vector with this temporary argument. So it's a move.
The second time, you are basically casting the thing that's already an rvalue reference to an rvalue reference, and so the move constructor is used again. There should be absolutely no difference between the behavior of both of them.
I think, maybe, you are misunderstanding what a temporary is and what an rvalue reference is. It's not often you have to use ::std::move and if you are using it, you should look carefully at the code you're using it in to make sure you're doing the right thing.
This code on Godbolt is proof that the copy constructor is never called. Here is the code being linked to:
#include <utility>
struct ICantBeCopied {
ICantBeCopied(ICantBeCopied const &) = delete;
ICantBeCopied(ICantBeCopied &&) {}
ICantBeCopied() {}
};
ICantBeCopied make_a_copy()
{
ICantBeCopied c;
return c;
}
void a_function()
{
ICantBeCopied a{make_a_copy()};
ICantBeCopied b{::std::move(make_a_copy())};
}

What std::vector in C++ really is? [duplicate]

This question already has answers here:
How is vector implemented in C++
(9 answers)
Closed 8 years ago.
Not so far I discovered, that I completely have no clue about nature of std::vector.
Let me explain:
Vector is growable, right? That means, inside it must somehow allocate/reallocate memory dynamically. Something like this:
class vector {
private:
int *data;
};
Okay. But such definition implies the fact that if we pass std::vector to another function by reference or by value -- there will be no difference between this two types of parameter passing, and both function will be able to modify data (unless vector is passed as const).
BUT! I tried the following and my idea failed:
void try_to_modify(vector<int> v) {
v[2] = 53;
}
int main() {
vector<int> v(3);
v[2] = 142;
try_to_modify(v);
cout << v[2] << '\n'; // output is: 142
return 0;
}
So where's the truth? What std::vector really is?
Thank you.
std::vector is a container, which internally manages its memory and provides a custom copy constructor. In this copy constructor, new memory is allocated and the existing data is copied over, which makes it a expensive operation. If you want to pass a vector without copying the contained data, you can pass by const reference, for example, const std::vector<int>&.
Let's take a look how to implement a basic container like std::vector.
template <typename T>
class MyVector
{
public:
MyVector (int size)
: data_ (new T[size])
, size_ (size)
{}
~MyVector ()
{
delete [] data_;
}
private:
T* data_ = nullptr;
int size_ = 0;
};
If we copy such an object, we'll have two problems. First, as you noticed, the memory will point to the same location. Second, we will have two destructors that will destruct the same memory, resulting in a double-free. So, let's add a copy constructor, which will be invoked whenever a copy is made.
MyVector (const MyVector& other)
: size_ (other.size_)
{
data_ = new T[size_];
std::copy (other.data_, other.data_ + size_, data_);
}
MyVector& operator= (const MyVector& other)
{
// allocate and copy here to allow for self-assignment
auto newData = new T[other.size_];
std::copy (other.data_, other.data_ + size_, newData);
delete [] data_;
size_ = other.size_;
data_ = newData;
return *this;
}
And that's how std::vector works internally.
This isn't so much a problem with vector as it is with pass-by-value and pass-by-reference arguments.
void try_to_modify (vector<int> vec) will send a copy of the original vector to the function and the function operates on a copy. The vector will copy the data when a copy is made. i.e. new pointer to new data.
However, if you define your function as: void try_to_modify(vector<int> & vec) then it will send the exact vector to the function and your function will operate on it.
Passing by reference is much faster for objects and is usually preferable, unless you have a specific need for a copy.

about this smart pointer class

I run into this code in a book, a simple smart pointer, have a few questions about it:
template <class T>
class SmartPointer {
public:
SmartPointer(T * ptr) {
ref = ptr;
ref_count = malloc(sizeof(unsigned));
*ref_count = 1;
}
SmartPointer(SmartPointer<T> & sptr) {
ref = sptr.ref;
ref_count = sptr.ref_count;
++*ref_count;
}
SmartPointer<T> & operator=(SmartPointer<T> & sptr) {
if (this != &sptr) {
ref = sptr.ref;
ref_count = sptr.ref_count;
++*ref_count;
}
return *this;
}
~SmartPointer() {
--*ref_count;
if (*ref_count == 0) {
delete ref;
free(ref_count);
ref = ref_count = NULL;
}
}
T* operator->() { return ref; }
T& operator*() { return *ref; }
protected:
T * ref;
unsigned * ref_count;
};
here are my questions:
1. why is the ref_count initialized by using malloc? why can't it be ref_count = new unsigned();
2. the = operator function, doesn't it need to clean up the old value? this code seems to cause a ref counting error.
Thanks,
This book you have is rubbish. You need to throw it away. This code doesn't even compile.
malloc is not any better than new unsigned(1). malloc() returns void* which needs to be cast to unsigned* which is obviously not done here.
You are right, the reference count of the object previously pointed to needs to be taken care of.
Why not try looking into the implementation of boost::shared_ptr or std::shared_ptr? It's very likely that you'll end up using it anyway.
why is the ref_count initialized by using malloc?
It can use std::new as well. The primary difference between new and malloc is that new provides an opportunity to suitably initialize your object by calling its constructor in addition to allocating dynamic memory.In case of in-built data type like unsigned int(as in your example code) essentially this important difference doesn't matter.
Note that usually std::new implementations also essentially call a malloc for memory allocation.
The = operator function, doesn't it need to clean up the old value? this code seems to cause a ref counting error
Indeed there is an error.
The = operator in this implementation checks if the pointer is being assigned to itself and if yes it correctly increases the reference count by 1, Since there is one more entity which shares this pointer after the = is called.
If the scenario is not self assignment then the implementation should reduce the reference count of the pointer being assigned to by 1, check if the count is 0 and if it is zero, deallocate the same.
This is bad code. Self-assignment is non-idiomatic, awful use of malloc, buggy reference counting implementation, no const on the copy assignment operator/constructor argument, and doesn't deal with SmartPointers that point to NULL. Throw your book away and get one that works.

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

Implementing Smart Pointer - Dynamic Allocation with templates

I'm in the process of writing a smart pointer countedptr and I've hit a speed bump. The basic function of countedptr is to work like any other smart pointer and also have a count of how many pointers are pointing to a single object. So far, the code is:
[SOLVED]
#include "std_lib_facilities.h"
template <class T>
class counted_ptr{
private:
T* pointer;
int* count;
public:
counted_ptr(T* p = 0, int* c = new int(1)) : pointer(p), count(c) {} // default constructor
explicit counted_ptr(const counted_ptr& p) : pointer(p.pointer), count(p.count) { ++*count; } // copy constructor
~counted_ptr() { --*count; delete pointer; }
counted_ptr& operator=(const counted_ptr& p)
{
pointer = p.pointer;
count = p.count;
++*count;
return *this;
}
T* operator->() const{ return pointer; }
T& operator*() const { return *pointer; }
int Get_count() const { return *count; }
};
int main()
{
counted_ptr<double> one;
counted_ptr<double>two(one);
int a = one.Get_count();
cout << a << endl;
}
When I try to do something like
one->pointer = new double(5);
then I get a compiler error saying "request for member 'pointer' in '*(&one)->counted_ptr::operator->with T = double' which is of non-class type double".
I considered making a function to do this, and while I could make a function to allocate an array of T's, I can't think of a way of making one for allocating actual objects. Any help is appreciated, thanks.
Old Solution
What about another assignment operator?
counted_ptr& counted_ptr::operator=(T* p)
{
if (! --*count) { delete count; }
pointer = p;
count = new int(1);
return *this;
}
...
one = new double(5);
Also, your destructor always deletes a shared pointer, which is probably what caused *one to be a random nomber. Perhaps you want something like:
counted_ptr::~counted_ptr() { if (! --*count) { delete pointer; delete count; } }
New Solution
As you want repointing a counted_ptr (eg one = new double(5)) to update all related counted_ptrs, place both the pointer and the count in a helper class, and have your pointer class hold a pointer to the helper class (you might already be headed down this path). You could go two ways in filling out this design:
Make the helper class a simple struct (and a private inner class) and place all the logic in the outer class methods
Make counted_ptr the helper class. counted_ptr maintains a reference count but doesn't automatically update the count; it's not a smart pointer, it only responds to release and retain messages. If you're at all familiar with Objective-C, this is basically its traditional memory management (autoreleasing aside). counted_ptr may or may not delete itself when the reference count reaches 0 (another potential difference from Obj-C). counted_ptrs shouldn't be copyable. The intent is that for any plain pointer, there should be at most one counted_ptr.
Create a smart_ptr class that has a pointer to a counted_ptr, which is shared among smart_ptr instances that are supposed to hold the same plain pointer. smart_ptr is responsible for automatically updating the count by sending its counted_ptr release and retain methods.
counted_ptr may or may not be a private inner class of shared_ptr.
Here's an interface for option two. Since you're doing this as an exercise, I'll let you fill out the method definitions. Potential implementations would be similar to what's already been posted except that you don't need a copy constructor and copy assignment operator for counted_ptr, counted_ptr::~counted_ptr doesn't call counted_ptr::release (that's smart_ptr::~smart_ptr's job) and counted_ptr::release might not free counted_ptr::_pointer (you might leave that up to the destructor).
// counted_ptr owns its pointer an will free it when appropriate.
template <typename T>
class counted_ptr {
private:
T *_pointer;
size_t _count;
// Make copying illegal
explicit counted_ptr(const counted_ptr&);
counted_ptr& operator=(const counted_ptr<T>& p);
public:
counted_ptr(T* p=0, size_t c=1);
~counted_ptr();
void retain(); // increase reference count.
bool release(); // decrease reference count. Return true iff count is 0
void reassign(T *p); // point to something else.
size_t count() const;
counted_ptr& operator=(T* p);
T& operator*() const;
T* operator->() const;
};
template <typename T>
class smart_ptr {
private:
counted_ptr<T> *_shared;
void release(); // release the shared pointer
void retain(); // retain the shared pointer
public:
smart_ptr(T* p=0, int c=1); // make a smart_ptr that points to p
explicit smart_ptr(counted_ptr<T>& p); // make a smart_ptr that shares p
explicit smart_ptr(smart_ptr& p); // copy constructor
~smart_ptr();
// note: a smart_ptr's brethren are the smart_ptrs that share a counted_ptr.
smart_ptr& operator=(smart_ptr& p); /* Join p's brethren. Doesn't alter pre-call
* brethren. p is non-const because this->_shared can't be const. */
smart_ptr& operator=(counted_ptr<T>& p); /* Share p. Doesn't alter brethren.
* p is non-const because *this isn't const. */
smart_ptr& operator=(T* p); // repoint this pointer. Alters brethren
size_t count() const; // reference count
T& operator*() const; // delegate these to _shared
T* operator->() const;
};
Hopefully, the only ambiguous points above are the intentional ones.
(Sorry, newbie here, and can't leave comments). What Adatapost added, "one=new double(5);" should work. One other change needed, though: the reference counting needs a little help.
...
~counted_ptr() {
--*count;
// deallocate objects whose last reference is gone.
if (!*count)
{
delete pointer;
delete count;
}
}
counted_ptr& operator=(const counted_ptr& p)
{
// be careful to accommodate self assignment
++*p.count;
// may lose a reference here
--*count;
if (!*count)
{
delete pointer;
delete count;
}
count=p.count;
pointer=p.pointer;
return *this;
}
Of course, there's some code repetition here. It might make sense to refactor that code into its own function, e.g.
private:
/** remove our reference */
void release()
{
--*count;
if (!*count)
{
delete pointer;
delete count;
}
}
Did you, perhaps, mean "one.pointer=new double(5);"? Writing "one->pointer=new double(5);" invokes counted_ptr<double>::operator->. That is, it is approximately equivalent to:
double *tmp = one.operator->(); // returns one.pointer
tmp->pointer = new double(5);
But a double pointer isn't a structure, and so it doesn't have a pointer member.
Since the immediate problem has already been solved, I want to offer something more long term:
As you continue to develop this code, you'll definitely want to offer it up for full review by experienced programmers, whether here or elsewhere. There were a few obvious problems with your code as you posted it, though outis has helped correct them. But even once your code all compiles and seems to work in your own tests, there may be tests and situations which you haven't yet learned to think about. Smart pointers can easily have subtle problems that don't show up until very specific situations. So you'll want others to look over your code to find anything which you may have missed.
Please don't take this as any kind of insult towards your current code. I'm just offering this as friendly advice to ensure you learn the most you can out of this project.
Unless you are not doing this for academic reasons, you might want to use consider using the use_count() member of boost::shared_ptr. It's not entirely efficient, but it does work and you're better off using something well tested, mature, and thread safe. If you are doing this for learning purposes, be sure to check out the treatment of Reference Counting and Smart Pointers in More Effective C++.
You need to decrement the count and possibly delete the pointer to the old value in operator = before you overwrite it. You also need 'delete count' everywhere you have 'delete pointer' to avoid leaking memory