After making a lot of changes to a project, I created an error that took me quite a while to track down.
I have a class which contains a dynamically allocated array. I then create a dynamic array of this class. I can then delete[] that array. But, if I replace an item in the array before deleting it, it causes an error. In debug mode, it gives an assertion message from dbgdel.cpp "Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)". Here is a small program to demonstrate.
class SomeClass {
public:
int *data;
SomeClass() {
data = nullptr;
}
SomeClass(int num) {
data = new int[num];
}
~SomeClass() {
if (data != nullptr) {
delete[] data;
}
}
};
int main(int argc, char *args[]) {
SomeClass *someArray = new SomeClass[10];
//If you comment this out, there is no error. Error gets thrown when deleting
someArray[0] = SomeClass(10);
delete[] someArray;
return 0;
}
I'm curious, why does this happen? When the item in the array gets replaced, its destructor gets called. Then the new item allocates its data in a location separate from the array. Then delete[] calls the destructors of all the objects in the array. When the destructors get called, they should delete the item's data array. I can't imagine what the problem is, but I'd like if someone could explain.
Your class is broken: It has a non-trivial destructor, but you do not define copy constructors and copy assignment operators. That means that the class cannot be correctly copied or assigned-to (since the destructible state is not copied or assigned appropriately), as you are noticing in your example code.
You can either make your class uncopiable (in which case your code won't compile any more), or move-only, in which case you need to define move construction and move-assignment, or properly copyable by implementing a deep copy of the data.
Here's how, add the following definitions:
Non-copyable:
SomeClass(SomeClass const &) = delete;
SomeClass & operator(SomeClass const &) = delete;
Moveable-only:
SomeClass(SomeClass const &) = delete;
SomeClass(SomeClass && rhs) : data(rhs.data) { rhs.data = nullptr; }
SomeClass & operator(SomeClass const &) = delete;
SomeClass & operator(SomeClass && rhs) {
if (this != &rhs) { delete data; data = rhs.data; rhs.data = nullptr; }
return *this;
}
Copyable:
SomeClass(SomeClass const & rhs) : ptr(new int[rhs->GetSizeMagically()]) {
/* copy from rhs.data to data */
}
SomeClass & operator(SomeClass const & rhs) {
if (this == &rhs) return *this;
int * tmp = new int[rhs->GetSizeMagically()];
/* copy data */
delete data;
data = tmp;
}
// move operations as above
The upshot is that the nature of the destructor determines the invariants of the class, because every object must be consistently destructible. From that you can infer the required semantics of the copy and move operations. (This is often called the Rule of Three or Rule of Five.)
Kerrek SB s answer is great. I just want to clarify that in your code memory is freed twice.
This code
someArray[0] = SomeClass(10);
is the same as this
SomeClass temp(10);
someArray[0] = temp; //here temp.data is copied to someArray[0].data
Then ~SomeClass() is called for temp and data is freed first time.
Here
delete[] someArray;
~SomeClass() is called for someArray[0] and data is freed second time.
Related
In c++ when classes contains dynamically allocated data it is usually reasonable to explicitly define copy constructor, operator= and destructor. But the activity of these special methods overlaps. More specifically operator= usually first does some destruction and then it does coping similar to the one in copy constructor.
My question is how to write this the best way without repeating the same lines of code and without the need for processor to do unnecessary work (like unnecessary copying).
I usually end up with two helping methods. One for construction and one for destruction. The first is called from both copy constructor and operator=. The second is used by destructor and operator=.
Here is the example code:
template <class T>
class MyClass
{
private:
// Data members
int count;
T* data; // Some of them are dynamicly allocated
void construct(const MyClass& myClass)
{
// Code which does deep copy
this->count = myClass.count;
data = new T[count];
try
{
for (int i = 0; i < count; i++)
data[i] = myClass.data[i];
}
catch (...)
{
delete[] data;
throw;
}
}
void destruct()
{
// Dealocate all dynamicly allocated data members
delete[] data;
}
public: MyClass(int count) : count(count)
{
data = new T[count];
}
MyClass(const MyClass& myClass)
{
construct(myClass);
}
MyClass& operator = (const MyClass& myClass)
{
if (this != &myClass)
{
destruct();
construct(myClass);
}
return *this;
}
~MyClass()
{
destruct();
}
};
Is this even correct?
And is it a good habit to split the code this way?
One initial comment: the operator= does not start by
destructing, but by constructing. Otherwise, it will leave the
object in an invalid state if the construction terminates via an
exception. Your code is incorrect because of this. (Note that
the necessity to test for self assignment is usually a sign that
the assignment operator is not correct.)
The classical solution for handling this is the swap idiom: you
add a member function swap:
void MyClass:swap( MyClass& other )
{
std::swap( count, other.count );
std::swap( data, other.data );
}
which is guaranteed not to throw. (Here, it just swaps an int
and a pointer, neither of which can throw.) Then you
implement the assignment operator as:
MyClass& MyClass<T>::operator=( MyClass const& other )
{
MyClass tmp( other );
swap( tmp );
return *this;
}
This is simple and straight forward, but any solution in which
all operations which may fail are finished before you start
changing the data is acceptable. For a simple case like your
code, for example:
MyClass& MyClass<T>::operator=( MyClass const& other )
{
T* newData = cloneData( other.data, other.count );
delete data;
count = other.count;
data = newData;
return *this;
}
(where cloneData is a member function which does most of what
your construct does, but returns the pointer, and doesn't
modify anything in this).
EDIT:
Not directly related to your initial question, but generally, in
such cases, you do not want to do a new T[count] in
cloneData (or construct, or whatever). This constructs all
of the T with the default constructor, and then assigns them.
The idiomatic way of doing this is something like:
T*
MyClass<T>::cloneData( T const* other, int count )
{
// ATTENTION! the type is a lie, at least for the moment!
T* results = static_cast<T*>( operator new( count * sizeof(T) ) );
int i = 0;
try {
while ( i != count ) {
new (results + i) T( other[i] );
++ i;
}
} catch (...) {
while ( i != 0 ) {
-- i;
results[i].~T();
}
throw;
}
return results;
}
Most often, this will be done using a separate (private) manager
class:
// Inside MyClass, private:
struct Data
{
T* data;
int count;
Data( int count )
: data( static_cast<T*>( operator new( count * sizeof(T) ) )
, count( 0 )
{
}
~Data()
{
while ( count != 0 ) {
-- count;
(data + count)->~T();
}
}
void swap( Data& other )
{
std::swap( data, other.data );
std::swap( count, other.count );
}
};
Data data;
// Copy constructor
MyClass( MyClass const& other )
: data( other.data.count )
{
while ( data.count != other.data.count ) {
new (data.data + data.count) T( other.date[data.count] );
++ data.count;
}
}
(and of course, the swap idiom for assignment). This allows
multiple count/data pairs without any risk of loosing exception
safety.
I don't see any inherent problem with that, as long as you make sure not to declare construct or destruct virtual.
You might be interested in chapter 2 in Effective C++ (Scott Meyers), which is completely devoted to constructors, copy operators and destructors.
As for exceptions, which your code is not handling as it should, consider items 10 & 11 in More effective C++ (Scott Meyers).
Implement the assignment by first copying the right-hand side and then swapping with that. This way you also get exception safety, which your code above doesn't provide. You could end up with a broken container when construct() fails after destruct() succeeded otherwise, because the member pointer references some deallocated data, and on destruction that will be deallocated again, causing undefined behaviour.
foo&
foo::operator=(foo const& rhs)
{
using std::swap;
foo tmp(rhs);
swap(*this, tmp);
return *this;
}
I do not know how to make constructors for an object with multiple raw pointers. I understand how to make it for one but do not understand multiple.
I have tried to write a new constructor during initialization, which then specifies what is accessed from the donor object.
I would like to know a way to make multiple constructors that extract different l values from one object depending on the order of initialization, however, I cannot find information about how to do this. I have some examples below.
class Movie {
publuc:
std::string *movie_name;
std::string *age_rating;
int *view_count;
int *rating;
Movie::Movie(const Movie &source , const Movie &source , const Movie &source , const Movie &source)
: {movie_name = new string;
*movie_name source;},
{age_rating = new string;
*age_rating source;},
{view_count = new int;
*view_count source;},
{source.rating = new int;
*source.rating source;}
I am at loss for understanding, I know I am missing something because this problem must be solvable. Please help me c++ master wherever you are.
You shouldn't be using raw pointers at all here. There is no reason for it. It's just an invitation to make tons of errors.
Secondly, the syntax you have for initializers is very broken, that's not how the syntax works at all. I'll put in an example of what initializers should look like in here so you can see. You also misunderstand what new does. You don't need any of the assignments that you're doing. Not one of them.
Also, you've misspelled public as publuc. And the way you declare your constructor is not correct for declaring it as a class member.
You know, almost all the problems you have, the compiler should've given you at least vaguely sensible error messages about, and you shouldn't need us to fix them for you.
Here is an example class that uses some pointer members. Note that if you are using pointer members, especially as a C++ beginner, you are almost certainly doing something wrong. Bare pointers should be among the last things you learn about in C++, not the first:
class IHaveSomePointers {
public:
IHaveSomePointers(bool const &mybool, int const &myint)
: mybool_{new bool(mybool)}, myint_{new int(myint)}
{ }
~IHaveSomePointers() {
delete mybool_;
delete myint_;
}
IHaveSomePointers(IHaveSomePointers const &) = delete;
void operator =(IHaveSomePointers const &) = delete;
private:
bool *mybool_;
int *myint_;
};
This class does have one problem. If allocation of myint_ throws an exception, there will be a memory leak. This kind of thing is why you do not use raw pointers in C++, especially for member variables, and most especially if the thing they're going to be pointing at is allocated with new.
I deleted the copy constructor and assignment operator because they need special implementations for classes that contain raw pointers. I notice that you appear to have been trying to define your own copy constructor, but it's hard to tell because your constructor declaration is so very garbled.
Here is how this class should be written:
class IDontHavePointersBecauseThatsBad {
public:
IDontHavePointersBecauseThatsBad(bool const &mybool, int const &myint)
: mybool_{mybool}, myint_{myint}
{ }
private:
bool mybool_;
int myint_;
};
If you absolutely must dynamically allocate things, do this:
#include <memory>
class ForSomeBizarreReasonIDyanmicallyAllocate {
public:
ForSomeBizarreReasonIDynamicallyAllocate(bool const &mybool, int const &myint)
: mybool_{::std::make_unique<bool>(mybool)},
myint_{::std::make_unique<int>(myint)}
{ }
private:
::std::unique_ptr<bool> mybool_;
::std::unique_ptr<int> myint_;
};
That class doesn't need a destructor to make sure it deletes the memory it allocates. It doesn't have a potential memory leak. It's all around a better class.
Your copy constructor is all wrong. It needs to look like this instead:
class Movie {
public:
std::string *movie_name;
std::string *age_rating;
int *view_count;
int *rating;
Movie(const Movie &source) :
movie_name(new string(*(source.movie_name))),
age_rating(new string(*(source.age_rating))),
view_count(new int(*(source.view_count))),
rating(new int(*(source.rating)))
{
}
...
};
You would also need to implement a destructor and a copy assignment operator, and in C++11 and later a move constructor and move assignment operator, per the Rule of 3/5/0, eg:
class Movie {
public:
std::string *movie_name;
std::string *age_rating;
int *view_count;
int *rating;
Movie() :
movie_name(new string),
age_rating(new string),
view_count(new int(0)),
rating(new int(0))
{
}
Movie(const Movie &source) :
movie_name(new string(*(source.movie_name))),
age_rating(new string(*(source.age_rating))),
view_count(new int(*(source.view_count))),
rating(new int(*(source.rating)))
{
}
Movie(Movie &&source) :
movie_name(source.movie_name),
age_rating(source.age_rating),
view_count(source.view_count),
rating(source.rating)
{
source.movie_name = nullptr;
source.age_rating = nullptr;
source.view_count = nullptr;
source.rating = nullptr;
}
~Movie()
{
delete movie_name;
delete age_rating;
delete view_count;
delete rating;
}
Movie& operator=(const Movie &source)
{
if (&source != this)
{
*movie_name = *(source.movie_name);
*age_rating = *(source.age_rating);
*view_count = *(source.view_count);
*rating = *(source.rating);
}
return *this;
}
Movie& operator=(Movie &&source)
{
Movie temp(std::move(source));
std::swap(movie_name, temp.movie_name);
std::swap(age_rating, temp.age_rating);
std::swap(view_count, temp.view_count);
std::swap(rating, temp.rating);
return *this;
}
};
You can mitigate some of the risk of manually managing memory allocations by using smart pointers:
#include <memory>
class Movie {
public:
std::unique_ptr<std::string> movie_name(new string);
std::unique_ptr<std::string> age_rating(new string);
std::unique_ptr<int> view_count(new int(0));
std::unique_ptr<int> rating(new int(0));
Movie() = default;
Movie(const Movie &source) :
movie_name(new string(*(source.movie_name))),
age_rating(new string(*(source.age_rating))),
view_count(new int(*(source.view_count))),
rating(new int(*(source.rating)))
{
}
Movie(Movie &&source) = default;
~Movie() = default;
Movie& operator=(const Movie &source)
{
if (&source != this)
{
*movie_name = *(source.movie_name);
*age_rating = *(source.age_rating);
*view_count = *(source.view_count);
*rating = *(source.rating);
}
return *this;
}
Movie& operator=(Movie &&source) = default;
};
But really, there is no good reason to be using pointers at all in this situation. Get rid of the pointers altogether and let the compiler auto-generate appropriate constructors, destructor, and assignment operators that do all of the hard work of managing memory and copying values for you:
class Movie {
public:
std::string movie_name;
std::string age_rating;
int view_count = 0;
int rating = 0;
// everything is auto-generated for you!
};
Thx you for the answers, this isn't homework though its late-night scribblings. I was really tired and trying to go ahead of what I have studied. Although on the bright side I haven't studied smart pointers yet so I feel less stupid, I just wanted to say thanks for being more constructive that I usually am over the internets.
I have an Array class written with RAII in mind (super simplified for the purpose of this example):
struct Array
{
Array(int size) {
m_size = size;
m_data = new int[m_size];
}
~Array() {
delete[] m_data;
}
int* m_data = nullptr;
int m_size = 0;
};
Then I have a function that takes a reference to an Array and does some operations on it. I use a temporary Array temp to perform the processing, because for several reasons I can't work directly with the reference. Once done, I would like to transfer the data from the temporary Array to the real one:
void function(Array& array)
{
Array temp(array.m_size * 2);
// do heavy processing on `temp`...
array.m_size = temp.m_size;
array.m_data = temp.m_data;
}
The obvious problem is that temp goes out of scope at the end of the function: its destructor is triggered, which in turn deletes the memory. This way array would contain non-existent data.
So what is the best way to "move" the ownership of data from an object to another?
What you want is move construction or move assignment for your array class, which saves you redundant copies. Also, it will help you to use std::unique_ptr which will take care of move semantics for allocated memory for you, so that you don't need to do any memory allocation directly, yourself. You will still need to pull up your sleeves and follow the "rule of zero/three/five", which in our case is the rule of five (copy & move constructor, copy & move assignment operator, destructor).
So, try:
class Array {
public:
Array(size_t size) : m_size(size) {
m_data = std::make_unique<int[]>(size);
}
Array(const Array& other) : Array(other.size) {
std::copy_n(other.m_data.get(), other.m_size, m_data.get());
}
Array(Array&& other) : m_data(nullptr) {
*this = other;
}
Array& operator=(Array&& other) {
std::swap(m_data, other.m_data);
std::swap(m_size,other.m_size);
return *this;
}
Array& operator=(const Array& other) {
m_data = std::make_unique<int[]>(other.m_size);
std::copy_n(other.m_data.get(), other.m_size, m_data.get());
return *this;
}
~Array() = default;
std::unique_ptr<int[]> m_data;
size_t m_size;
};
(Actually, it's a bad idea to have m_size and m_data public, since they're tied together and you don't want people messing with them. I would also template that class on the element type, i.e. T instead of int and use Array<int>)
Now you can implement your function in a very straightforward manner:
void function(Array& array)
{
Array temp { array }; // this uses the copy constructor
// do heavy processing on `temp`...
std::swap(array, temp); // a regular assignment would copy
}
if you insist on your example format, then you are missing a couple of things. you need to make sure that the temp array does not destroy memory reused by the non-temp array.
~Array() {
if (md_data != nullptr)
delete [] m_data;
}
and the function needs to do clean move
void function(Array& array)
{
Array temp(array.m_size * 2);
// do heavy processing on `temp`...
array.m_size = temp.m_size;
array.m_data = temp.m_data;
temp.m_data = nullptr;
temp.m_size = 0;
}
To make it more c++ like, you can do multiple things. i.e. in the array you can create member function to move the data from other array (or a constructor, or assign operator, ...)
void Array::move(Array &temp) {
m_size = temp.m_size;
temp.m_size = 0;
m_data = temp.m_data;
temp.m_data = 0;
}
in c++11 and higher you can create a move constructor and return your value from the function:
Array(Array &&temp) {
do your move here
}
Array function() {
Array temp(...);
return temp;
}
there are other ways as well.
Code like this from one of my books for example:
class HasPtr {
public:
HasPtr(const HasPtr& h): ps(new std::string(*h.ps)), i(h.i) { }
HasPtr(const std::string &s = std::string()): ps(new std::string(s)), i(0) { }
HasPtr& operator=(const HasPtr&);
~HasPtr() { delete ps; }
private:
std::string *ps;
int i;
};
HasPtr& HasPtr::operator=(const HasPtr &rhs){
auto newp = new string(*rhs.ps); // copy the underlying string
delete ps; // free the old memory
ps = newp; // copy data from rhs into this object
i = rhs.i;
return *this; // return this object
}
Seems like the inside of the operator= could just be:
*ps = *rhs.ps
i = rhs.i
return *this;
With no need to delete the pointer first, seems redundant to do so. It did mention it is written in a way to leave the object in a suitable state should an exception occur but didn't divulge past that, but I don't see what exception could occur that even my alternative wouldn't handle. Why is there a need to delete the object first before assigning?
In this case, yes, that would be fine.
You're not leaking the dynamically-allocated string: you're re-using it.
This looks fine to me.
And you're right, std::string assignment already offers a strong exception guarantee so you will still leave the object in its original state should an exception occur copying the string.
Of course there is no reason to allocate a std::string with new like that. You could just write this instead:
class HasNoPtr {
public:
HasNoPtr(const std::string& s): ps(s), i(0) { }
private:
std::string ps;
int i;
};
I can't figure out why I get error for the code below.
The instances of object A will be pushed into a vector (vectorA.push_back(A a)) continuously. So sometimes, vectorA needs to be reallocated; the destructor will be called, which is where the destructor of A gets called, then the error message appears.
class A
{
long filePos;
union {
Recording* recording;
UINT64 timeStamp;
};
public:
inline A(long fpos, UINT64 ts) : filePos(fpos), timeStamp(ts) {}
~A()
{
if (getDetailedType() == RECORDING_TYPE)
if (recording)
delete recording; // error: scalar deleting destructor ???
}
inline short getDetailedType() const { return (short)(timeStamp % 5); }
A(const A& edi)
{
filePos = edi.filePos;
if (getDetailedType() == RECORDING_INFO)
recording = edi.recording;
else
timeStamp = edi.timeStamp;
}
}
class Recording : protected RECORDINGS
{
UINT64 timestamp;
float scalar;
public:
~Recording() // with or without this dtor, got same error
{
}
inline Recording()
{
timestamp = 0;
scalar = 2.0;
time = 0;
rate = 30;
type = 1;
side = 1;
}
}
typedef struct
{
UINT32 time;
float rate;
int type;
int side;
} RECORDINGS;
Your copy constructor does a shallow copy. So, now you have two objects that both have the same recording pointer.
You should either do a deep copy, or ensure the ownership is properly transferred (by using something like std::unique_ptr<Recording> if C++11 is available.
See This question on the difference between deep and shallow copies.
Let's look at some examples:
class ABadCopyingClass
{
public:
ABadCopyingClass()
{
a_ = new int(5);
}
~ABadCopyingClass()
{
delete a_;
}
private:
int* a_;
};
The above class is bad because the default copy constructor and assignment operator will perform a shallow copy, and lead to two objects both thinking that they own the underlying a_ object. When one of them goes out of scope, the a_ will be deleted, and the other one will be left with a dangling pointer that will eventually lead to a crash.
class ABetterCopyingClass
{
public:
ABetterCopyingClass()
a_(new int(5))
{
}
ABetterCopyingClass(const ABetterCopyingClass& r)
{
a_ = new int(*r.a_);
}
ABetterCopyingClass& operator=(const ABetterCopyingClass& r)
{
// in the case of reassignment...
delete a_;
a_ = new int(*r.a_);
return *this;
}
~ABetterCopyingClass()
{
delete a_;
}
private:
int* a_;
};
This class improved our situation a little (note, that the normal error checking is left out in this simple example). Now the copy constructor and assignment operator properly perform the necessary deep copying. The drawback here is the amount of boilerplate code we had to add -- it's easy to get that wrong.
class ACannonicalCopyingClass
{
public:
ACannonicalCopyingClass()
: a_(new int(5))
{
}
ACannonicalCopyingClass(ACannonicalCopyingClass&& moved_from)
{
a_ = std::move(moved_from.a_);
}
private:
std::unique_ptr<int> a_;
};
This example (C++11 only) is even better. We've removed a significant amount of boilerplate code, however the semantics here are a bit different. Instead of deep copying, we get in this case transfer of ownership of the underlying a_ object.
The easiest version (C++11 only) to implement is the version that provides shared ownership of the underlying a_ object. This is the version that is most similar to your provided example, with the added bonus that it does not cause a crash.
class ASharedCopyingClass
{
public:
ASharedCopyingClass()
: a_(std::make_shared<int>(5))
{
}
private:
std::shared_ptr<int> a_;
};
This version can be copied at will, and the underlying a_ object will happily be reference counted. The last copy to go out of scope will set the reference count to 0, which will trigger the memory deallocation.
My psychic debugging skills tell me that you forgot to implement a copy constructor for A which then results in a double deletion of a Recording when the copy is destroyed.
The growth of the vector would trigger the copy-destroy pairs.