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;
}
Related
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);
}
I just came across some container implementation in C++. That class uses an internal buffer to manage its objects. This is a simplified version without safety checks:
template <typename E> class Container
{
public:
Container() : buffer(new E[100]), size(0) {}
~Container() { delete [] buffer; }
void Add() { buffer[size] = E(); size++; }
void Remove() { size--; buffer[size].~E(); }
private:
E* buffer;
int size;
};
AFAIK this will construct/destruct E objects redundantly in Container() and ~Container() if new/delete are not customized. This seems dangerous.
Is using placement new in Add() the best way to prevent dangerous redundant constructor / destructor calls (apart from binding the class to a fully featured pool)?
When using placement new, would new char[sizeof(E)*100] be the correct way for allocating the buffer?
AFAIK this will construct/destruct E objects redundantly
It would appear so. The newed array already applies the default constructor and the delete[] would call destructor as well for all the elements. In effect, the Add() and Remove() methods add little other than maintain the size counter.
When using placement new, would new char[sizeof(E)*100] be the correct way for allocating the buffer?
The best would be to opt for the std::allocator that handles all of the memory issues for you already.
Using a placement new and managing the memory yourself requires you to be aware of a number of issues (including);
Alignment
Allocated and used size
Destruction
Construction issues such as emplacement
Possible aliasing
None of these are impossible to surmount, it has just already been done in the standard library. If you are interested in pursuing a custom allocator, the global allocation functions (void* operator new (std::size_t count);) would be the appropriate starting point for the memory allocations.
Without further explanation on the original purpose of the code - a std::vector or a std::array would be far better options for managing the elements in the container.
There's a number of issues with the code.
If you call Remove() before calling Add() you will perform assignment to a destructed object.
Otherwise the delete[] buffer will call the destructor of 100 objects in the array. Which may have been called before.
Here's a valid program:
#include <iostream>
int counter=0;
class Example {
public:
Example():ID(++counter){
std::cout<<"constructing "<<ID<<std::endl;
}
~Example(){
std::cout<<"destructing "<<ID<<std::endl;
ID=-1;
}
private:
int ID;
};
template <typename E> class Container
{
public:
Container() : buffer(new char [100*sizeof(E)]), size(0) {}
~Container() {
for(size_t i=0;i<size;++i){
reinterpret_cast<E*>(buffer)[i].~E();
}
delete [] buffer;
}
void Add() { new (buffer+sizeof(E)*size) E(); size++; }
void Remove() { reinterpret_cast<E*>(buffer)[--size].~E(); }
private:
void* buffer;
size_t size;
};
int main() {
Container<Example> empty;
Container<Example> single;
Container<Example> more;
single.Add();
more.Add();
more.Remove();
more.Add();
more.Add();
more.Remove();
return 0;
}
I build a class for containing vectors with no default constructor. Specifically:
template<typename T>
struct MyVector
{
public:
int GetN(void)
{
return n;
}
MyVector(int n1)
{
n=n1;
ListElt = new T[n1];
}
~MyVector()
{
delete [] ListElt;
}
// some other irrelevant to the question code
private:
int n;
T *ListElt;
};
Now I want to build a class derived from it that contains one integer and a vector.
The code that works is the following:
struct EquivInfo {
public:
EquivInfo(int inpOrbit, MyVector<int> &inpMat)
{
iOrbit=inpOrbit;
eVect=new MyVector<int>(inpMat.getN());
// some code for copying the vector in place.
}
~EquivInfo()
{
delete eVect;
}
private:
int iOrbit;
MyVector<int> *eVect;
};
Is there a way to avoid the use of the pointer for the vector?
The problem is that if I remove the pointer then there is a call to a constructor of the kind MyVector(). I do not understand why. There should be a way to have a constructor for EquivInfo that calls a precise constructor for MyVector
I could add a constructor MyVector(), i.e. a default constructor that set the vector to something trivial. But precisely, I want to avoid such kind of constructors so that all vectors are well defined and the code is clean. The use of the pointer allows me to have a reasonable situation but I wonder if there is a clean way to avoid it.
Use member initializer list:
class EquivInfo {
public:
EquivInfo(int inpOrbit, MyVector<int> &inpMat)
: eVect(inpMat.getN())
, iOrbit(inpOrbit) {
// some code for copying the vector in place.
}
// ....
MyVector<int> eVect;
}
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.
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.