I am currently trying to figure out how to do move semantics correctly with an object which contains a pointer to allocated memory. I have a big datastructure, which contains an internal raw pointer to the actual storage (for efficiency reasons). Now I added a move constructor and move operator=(). In these methods I am std::move()ing the pointer to the new structure. However I am not sure what to do with the pointer from the other structure.
Here is a simple example of what I am doing:
class big_and_complicated {
// lots of complicated code
};
class structure {
public:
structure() :
m_data( new big_and_complicated() )
{}
structure( structure && rhs ) :
m_data( std::move( rhs.m_data ) )
{
// Maybe do something to rhs here?
}
~structure()
{
delete m_data;
}
private:
big_and_complicated * m_data;
}
int main() {
structure s1;
structure s2( std::move( s1 ) );
return 0;
}
Now from what I understand, after the std::move( s1 ) to s2 the only thing that is safe to do on s1 ist to call its constructor. However as far as I can see, this would lead to deleting the pointer contained within s1 in the destructor, rendering s2 useless as well. So I am guessing I have to do something to render the destructor safe when std::move()ing the pointer. As far as I can see the safest thing to do here, is to set it to 0 in the moved object, since this would turn the delete into a no-op later on. Is this reasoning correct so far? Or is std::move() actually smart enough to null out the pointer for me, rendering its usage safe? So far I am seeing no crashes in the actual test-suite, but I have not made sure the move-constructor is actually called.
"Moving" a pointer is no different than copying one and does not set the moved-from value to null ('moving' is in quotes here because std::move does not move anything really, it just changes the value category of the argument). Just copy rhs's pointer then set it to nullptr:
struct structure
{
structure()
: m_data{new big_and_complicated{}}
{ }
structure(structure&& rhs)
: m_data{rhs.m_data}
{
rhs.m_data = nullptr;
}
structure& operator =(structure&& rhs)
{
if (this != &rhs)
{
delete m_data;
m_data = rhs.m_data;
rhs.m_data = nullptr;
}
return *this;
}
~structure()
{
delete m_data;
}
private:
big_and_complicated* m_data;
structure(structure const&) = delete; // for exposition only
structure& operator =(structure const&) = delete; // for exposition only
}
You could also simplify this by using std::exchange:
structure(structure&& rhs)
: m_data{ std::exchange(rhs.m_data, nullptr) }
{ }
structure& operator=(structure&& rhs)
{
if (this != &rhs)
{
delete m_data;
m_data = std::exchange(rhs.m_data, nullptr);
}
return *this;
}
Better yet, use std::unique_ptr<big_and_complicated> instead of big_and_complicated* and you don't need to define any of this yourself:
#include <memory>
struct structure
{
structure()
: m_data{new big_and_complicated{}}
{ }
private:
std::unique_ptr<big_and_complicated> m_data;
}
Lastly, unless you actually want structure to remain non-copyable, you're better off just implementing proper move semantics inside of big_and_complicated and having structure hold a big_and_complicated object directly.
Related
I am having trouble with writing the Rule of three when it comes to vector of pointers to class objects. Searched and examples don't seem to apply. I have these three classes:
class Data
{
private:
map<string, double> m_DataVariables;
public:
Data();
Data(const Data &data);
};
class Sample
{
private:
Data *m_pData;
public:
virtual ~Sample()
{
delete m_pData;
}
Sample();
Sample(const Sample &sample);
};
class BuildTree
{
private:
vector<Sample*> BuildSamples;
public:
BuildTree(vector<Sample*> &Samples);
// This does not compile
BuildTree(const BuildTree& other) : BuildSamples(new(other.BuildSamples))
{
}
~TreeBuilding()
{
for (int i = 0; i < BuildSamples.size(); ++i)
delete BuildSamples[i];
}
void BuildTrees(void);
};
1- Not sure if I am correctly deleting BuildSamples.
2- In the constructor want to do a deep copy of the passed parameter into member variable BuildSamples.
BuildTree::BuildTree(vector<Sample*> &samples)
{
BuildSamples = samples; // This just copies the references
}
How do I write the copy constructor to make a deep copy? What am I missing here?
3- Please note: don't have access to smart pointers, share_ptr or unique_ptr, etc. C++98 is what I have.
Please show the steps required to do this. Really appreciate your time and consideration.
I noted you marked your question as c++98; even if C++98 doesn't support smart pointers in std::, you can certainly use the smart pointers defined in Boost, e.g. boost::shared_ptr.
For example, instead of using raw owning pointers like in vector<Sample*>, you can make your code simpler with
vector<boost::shared_ptr<Sample>>.
In this way, the copy and destruction operations will be automatically implemented under the hood.
You probably want something like:
BuildTree(const BuildTree& other)
{
BuildSamples.reserve(other.BuildSamples.size());
for (std::size_t i = 0; i != other.BuildSamples.size(); ++i) {
BuildSamples.push_back(new Sample(*other.BuildSamples[i]));
}
}
BuildTree(const vector<Sample*> &samples)
{
BuildSamples.reserve(samples.size());
for (std::size_t i = 0; i != samples.size(); ++i) {
BuildSamples.push_back(new Sample(*samples[i]));
}
}
You need to initialise the BuildSamples member as a vector of pointers, and ensure every pointer points at a clone of the objects passed. One way is
BuildTree(const BuildTree& other) : BuildSamples(other.BuildSamples)
{
std::vector<Sample *>::iterator i = BuildSamples.begin(), end = BuildSamples.end();
while (i != end)
{
*i = new Sample(**i);
++i;
}
}
The usage of BuildSamples(other.BuildSamples) initialises BuildSamples with the correct number of elements, but those elements are the same pointers as in other.BuildSamples. This ensures the vector is of the correct size, without worrying about setting the size explicitly. That is a shallow copy. The body of the constructor then sets every element of BuildSamples so it points at a clone of itself - thus completes the deep copy.
The constructor BuildTree(const std::vector<Sample *> &) can be implemented in a similar manner.
Note: given that your class is implementing a non-trivial copy constructor (to do the deep copy) and a destructor to cleanup, you also need to implement an assignment operator BuildTree &operator=(const BuildTree &). For an explanation why, look up the "rule of three".
While dealing with pointers and to avoid crashing of a running program due to destructor being called, Deep copy must be used! deep copy allows creating a new pointer pointing to a newly allocated space. But when passing objects as R-value in vector it is better to use the move constructor.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class example{
private:
int *pointer;
public:
//constructor
example(int d){
pointer = new int;
*pointer = d;
cout<<"Constructor Called"<<endl;
}
// deep copy
example(const example &source){
pointer = new int;
*pointer= *source.pointer;
cout<<"deep copy made"<<endl;
}
// Move Constructor
example(example &&source) noexcept :pointer{source.pointer}{
source.pointer = nullptr;
cout << "object moved"<<endl;
}
// Destructor
~example() {
delete pointer;
cout << "Destroyed"<<endl;
}
};
int main()
{
vector <example> vec;
vec.push_back(example{300});
vec.push_back(example{300});
vec.push_back(example{300});
vec.push_back(example{300});
return 0;
}
Edit: made Foo and Bar a little less trivial, and direct replacement with shared_ptr<> more difficult.
Should unique_ptr<> be used as an easier way to implement move semantics?
For a class like
class Foo
{
int* m_pInts;
bool usedNew;
// other members ...
public:
Foo(size_t num, bool useNew=true) : usedNew(useNew) {
if (usedNew)
m_pInts = new int[num];
else
m_pInts = static_cast<int*>(calloc(num, sizeof(int)));
}
~Foo() {
if (usedNew)
delete[] m_pInts;
else
free(m_pInts);
}
// no copy, but move
Foo(const Foo&) = delete;
Foo& operator=(const Foo&) = delete;
Foo(Foo&& other) {
*this = std::move(other);
}
Foo& operator=(Foo&& other) {
m_pInts = other.m_pInts;
other.m_pInts = nullptr;
usedNew = other.usedNew;
return *this;
}
};
Implementing move becomes more tedious as data members are added. However, the moveable data can be placed in a separate struct, an instance of which is managed by unique_ptr<>. This allows =default to be used for move:
class Bar
{
struct Data
{
int* m_pInts;
bool usedNew;
// other members ...
};
std::unique_ptr<Data> m_pData = std::make_unique<Data>();
public:
Bar(size_t num, bool useNew = true) {
m_pData->usedNew = useNew;
if (m_pData->usedNew)
m_pData->usedNew = new int[num];
else
m_pData->m_pInts = static_cast<int*>(calloc(num, sizeof(int)));
}
~Bar() {
if (m_pData->usedNew)
delete[] m_pData->m_pInts;
else
free(m_pData->m_pInts);
}
// no copy, but move
Bar(const Bar&) = delete;
Bar& operator=(const Bar&) = delete;
Bar(Bar&& other) = default;
Bar& operator=(Bar&& other) = default;
};
Other than the memory for the unique_ptr<> instance always being on the heap, what other problems exist with an implementation like this?
Yes. What you're looking for is called the Rule of Zero (as the C++11 extension of the Rule of Three/Five). By having your data all know how to copy and move themselves, the outer class doesn't need to write any of the special member functions. Writing those special members can be error-prone, so not having to write them solves a lot of problems.
So Foo would become just:
class Foo
{
std::unique_ptr<size_t[]> data;
public:
Foo(size_t size): data(new size_t[size]) { }
};
and that's very easy to prove the correctness of.
This is known as the rule of zero.
The rule of zero states that most classes do not implement copy/move assignment/construction or destruction. Instead, you delegate that to resource handling classes.
The rule of 5 states that if you implement any one of the 5 copy/move assign/ctor or dtor, you should implement or delete all 5 of them (or, after due consideration, default them).
In your case, the m_pInts should be a unique pointer, not a raw memory handled buffer. If it is tied to something (say a size), then you should write a pointer-and-size structure that implements the rule of 5. Or you just use a std::vector<int> if the overhead of 3 pointers instead of 2 is acceptable.
Part of this is that you stop invoking new directly. new is an implementation detail in the rule-of-5 types that manage resources directly. Business logic classes do not mess with new. They neither new, nor delete.
unique_ptr is just one of a category of resource-managing types. std::string, std::vector, std::set, shared_ptr, std::future, std::function -- most C++ std types qualify. Writing your own is also a good idea. But when you do, you should strip the resource code from the "business logic".
So if you wrote a std::function<R(Args...)> clone, you'd either use a unique_ptr or a boost::value_ptr to store the function object internal guts. Maybe you'd even write a sbo_value_ptr that sometimes exists on the heap, and sometimes locally.
Then you'd wrap that with the "business logic" of std::function that understands that the thing being pointed to is invokable and the like.
The "business logic" std::function would not implement copy/move assign/ctor, nor a destructor. It would probably =default them explicitly.
My advice would be to separate concerns and use composition.
Managing the lifetime of allocated memory is the job of a smart pointer. How to return that memory (or other resource) to the runtime is the concern of the smart pointer's deleter.
In general, if you find yourself writing move operators and move constructors it's because you have not sufficiently decomposed the problem.
Example:
#include <cstring>
#include <memory>
// a deleter
//
struct delete_or_free
{
void operator()(int* p) const
{
if (free_) {
std::free(p);
}
else {
delete [] p;
}
}
bool free_;
};
class Foo
{
//
// express our memory ownership in terms of a smart pointer.
//
using ptr_type = std::unique_ptr<int[], delete_or_free>;
ptr_type ptr_;
// other members ...
//
// some static helpers (reduces clutter in the constructor)
//
static auto generate_new(int size) {
return ptr_type { new int[size], delete_or_free { false } };
}
static auto generate_calloc(int size) {
return ptr_type {
static_cast<int*>(calloc(size, sizeof(int))),
delete_or_free { true }
};
}
public:
//
// our one and only constructor
//
Foo(size_t num, bool useNew=true)
: ptr_ { useNew ? generate_new(num) : generate_calloc(num) }
{
}
// it's good manners to provide a swap, but not necessary.
void swap(Foo& other) noexcept {
ptr_.swap(other.ptr_);
}
};
//
// test
//
int main()
{
auto a = Foo(100, true);
auto b = Foo(200, false);
auto c = std::move(a);
a = std::move(b);
b = std::move(c);
std::swap(a, b);
}
Say I have a simple data class:
struct Foo
{
int iData;
double dData;
};
I can create a container class that could be implemented as:
Version 1
struct Bar
{
std::vector<std::shared_ptr<Foo>> fooData;
};
or as:
Version 2
struct Bar
{
Bar(){}
Bar(Bar const& copy)
{
for(auto fooPtr: copy.fooData)
{
fooData.push_back(new Foo(*fooPtr));
}
}
~Bar()
{
for(auto fooPtr: fooData)
{
delete fooPtr;
}
}
Bar& operator=(Bar const& rhs)
{
if ( this == &rhs )
{
return *this;
}
for(auto fooPtr: fooData)
{
delete fooPtr;
}
fooPtr.clear(); // Had missed this in the original code.
for(auto fooPtr: rhs.fooData)
{
fooData.push_back(new Foo(*fooPtr));
}
return *this;
}
std::vector<Foo*> fooData;
};
Granted that Version 1 is a lot simpler and easier to maintain than Version 2.
However, I have couple of questions that are orthogonal to that aspect of the code.
Is Version 1 safer than Version 2 from the point of view of dealing with exceptions?
If so, how?
Yes, the first option is more exception safe. Namely, your copy constructor has two memory leak sources, the copy assignment operator has a memory leak and is simply plain wrong. Additionally, the first option has move assignment and a move constructor by default, giving improved performance. (Even more performance if you used std::unique_ptr instead)
Bar(Bar const& copy)
{
for(auto fooPtr: copy.fooData)
{
fooData.push_back(new Foo(*fooPtr));
//what happens if `new Foo` throws a bad_alloc?
//or if `Foo(const Foo&)` changes and now throws something?
//or if `fooData.push_back` throws a bad_alloc?
//anything you 'new'd is leaked.
}
}
Bar& operator=(Bar const& rhs)
{
if ( this == &rhs )
return *this;
for(auto fooPtr: fooData)
delete fooPtr;
//You forgot this line:
//fooData.clear();
for(auto fooPtr: rhs.fooData) //sharth notes you wrote copy.fooData but that's obvious
fooData.push_back(new Foo(*fooPtr));
//what happens if `fooData.push_back` throws a bad_alloc?
//the `Foo` you just created is leaked.
return *this;
}
Version 1 and version 2 have different semantics. If you copy a Bar object, version one gives shared access to the data, while version 2 does not. Version 2 also has a subtle memory leak; if new succeeds while push_back fails, the object leaks.
Why not use the even simpler std::vector<Foo>? I'm not seeing any rationale for using pointers (either shared or raw) in this case. Value semantics are much, much easier to reason about than pointer semantics.
I'm having trouble storing instances of my smart pointer into a container. Here is the code for the pointer.
#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;
if(!*count) {
delete pointer;
delete count;
}
}
counted_ptr& operator=(const counted_ptr& p) // copy assignment
{
pointer = p.pointer;
count = p.count;
++*count;
return *this;
}
T* operator->() const{ return pointer; }
T& operator*() const { return *pointer; }
int& operator[](int index) { return pointer[index]; }
int Get_count() const { return *count; } // public accessor for count
};
int main()
{
counted_ptr<double>one;
counted_ptr<double>two(one);
one = new double(5);
vector<counted_ptr<double> >test;
}
In int main(), the vector<counted_ptr<double> > line does compile. When I first tried it with just vector<counted_ptr<double> > it didn't compile (probably because it was lacking parameters.) However, when I try to use push_back such as
test.push_back(one);
I get a compiler error that opens up vector.tcc with the specific error saying that
no matching function for call to `counted_ptr<double>::counted_ptr(const counted_ptr<double>&)'|
I'm guessing that push_back can't find a counted_ptr, but I'm really not sure. Any
help is appreciated, thanks.
Edit: However, this works. test[0] = one; I guess the semantics of push_back are what is restricting it.
You may want to try this:
test.push_back(counted_ptr<double>(one));
You copy constructor is explicit which means that the compiler won't implicitly invoke it.
Personally, I would make the raw pointer constructor explicit and the copy ctor not explicit. That would be closer to usual behavior.
EDIT: I also recommend that you implement a swap method. It makes assignment absolutely trivial. You end up with something like this:
counted_ptr &operator=(const counted_ptr &rhs) {
counted_ptr(rhs).swap(*this);
return *this;
}
This also has the benefit of all of the accounting happening in constructors/destructors which is a lot simpler to manage :-).
Your assignment operator is wrong.
What happened to the object it was pointing at?
What happens if you are assigning to yourself or the same internal object?
counted_ptr& operator=(const counted_ptr& p) // copy assignment
{
if (&p != this)
{
--*count;
if ((*count) == 0) // Much more readable than !*count
{
delete pointer;
delete count;
}
pointer = p.pointer;
count = p.count;
++*count;
}
return *this;
}
Note: Writing your own smart pointer is not a good idea.
They are not as trivial to write as you think.
Note: This is the first thing I spotted. There could be more, and I am not sure this is 100% correct.
In fact I would change the assignment operator to use copy/swap idium.
counted_ptr& operator=(const counted_ptr& p) // copy assignment
{
counted_ptr<T> tmp(p); // increment counter on p
swap(tmp.pointer, pointer);
swap(tmp.count count);
return *this;
// tmp goes out of scope and thus the
// destructor gets called and what was in this
// object is now destroyed correctly.
}
// It may even be worth writing your own swap operator.
// Make sure you declare it as no-throw and grantee it.
I need a shared_ptr like object, but which automatically creates a real object when I try to access its members.
For example, I have:
class Box
{
public:
unsigned int width;
unsigned int height;
Box(): width(50), height(100){}
};
std::vector< lazy<Box> > boxes;
boxes.resize(100);
// at this point boxes contain no any real Box object.
// But when I try to access box number 50, for example,
// it will be created.
std::cout << boxes[49].width;
// now vector contains one real box and 99 lazy boxes.
Is there some implementation, or I should to write my own?
It's very little effort to roll your own.
template<typename T>
class lazy {
public:
lazy() : child(0) {}
~lazy() { delete child; }
T &operator*() {
if (!child) child = new T;
return *child;
}
// might dereference NULL pointer if unset...
// but if this is const, what else can be done?
const T &operator*() const { return *child; }
T *operator->() { return &**this; }
const T *operator->() const { return &**this; }
private:
T *child;
};
// ...
cout << boxes[49]->width;
Using boost::optional, you can have such a thing:
// 100 lazy BigStuffs
std::vector< boost::optional<BigStuff> > v(100);
v[49] = some_big_stuff;
Will construct 100 lazy's and assign one real some_big_stuff to v[49]. boost::optional will use no heap memory, but use placement-new to create objects in a stack-allocated buffer. I would create a wrapper around boost::optional like this:
template<typename T>
struct LazyPtr {
T& operator*() { if(!opt) opt = T(); return *opt; }
T const& operator*() const { return *opt; }
T* operator->() { if(!opt) opt = T(); return &*opt; }
T const* operator->() const { return &*opt; }
private:
boost::optional<T> opt;
};
This now uses boost::optional for doing stuffs. It ought to support in-place construction like this one (example on op*):
T& operator*() { if(!opt) opt = boost::in_place(); return *opt; }
Which would not require any copy-ing. However, the current boost-manual does not include that assignment operator overload. The source does, however. I'm not sure whether this is just a defect in the manual or whether its documentation is intentionally left out. So i would use the safer way using a copy assignment using T().
I've never heard of such a thing, but then again there are lots of things I've never heard of. How would the "lazy pointer" put useful data into the instances of the underlying class?
Are you sure that a sparse matrix isn't what you're really looking for?
So far as I know, there's no existing implementation of this sort of thing. It wouldn't be hard to create one though.