i try to use the std::map with
class DEMO {
public:
DEMO();
virtual ~DEMO();
DEMO &operator =(const DEMO &d);
DEMO(const DEMO& d);
BYTE* Arr() const;
private:
BYTE *m_array;
};
DEMO &DEMO::operator =(const DEMO &d) {
memcpy(m_array, d.Arr(), 1);
return *this;
}
DEMO::DEMO(const DEMO& d) {
//call operator=
*this = d;
}
const BYTE* DEMO::Arr() const {
return m_array;
}
DEMO::DEMO() {
m_array = new BYTE[1];
}
DEMO::~DEMO() {
if (m_array != 0)
delete [] m_array;
}
class MyClass {
private:
typedef map<unsigned int,DEMO> t_mapType;
t_mapType m_map;
void Test();
}
void MyClass::Test() {
DEMO myDEMO;
m_map[1] = myDEMO;
}
if i call Test() within the class, i get the error assert _CrtIsValidHeapPointer...
i checked with breakpoints and i see, during assingment (m_map[1] = myDEMO;) the destructor of DEMO gets called and i get the error on delete [] m_array; - how i make this running ?
The copy constructor and assignment operators are wrong. You need to allocate memory for m_array before doing memcpy. When you try to insert a DEMO object into the map using m_map[1] = myDEMO; a copy of the myDEMO is being created. To create a copy the DEMO class's copy ctor is used. Since the memory for m_array is not allocated while doing this copy, the memcpy call is crashing.
It's almost always wrong to base the copy ctor implementation on the assignment operator's. An assignment operator has to tear down the object's old state and build a new state. The copy ctor only has to build a new state.
If you want to do it this way, your copy ctor first needs to build a default state for the assignment operator to tear down. Of course, that's wasting resources.
That said, actually you should use the copy-and-swap idiom to base your assignment operator on your dtor and copy ctor instead. See here for a more thorough explanation of the above.
Use a std::vector to manage your BYTE*.
class DEMO {
public:
DEMO();
virtual ~DEMO();
//DEMO &operator =(const DEMO &d);
//DEMO(const DEMO& d);
const std::vector<BYTE>& Arr() const;
private:
std::vector<BYTE> m_array;
};
// Doesn't even need to be implemented by us anymore
//DEMO &DEMO::operator =(const DEMO &d) {
// memcpy(m_array, d.Arr(), 1);
// return *this;
//}
// Again, doesn't need to be implemented
//DEMO::DEMO(const DEMO& d) {
// //call operator=
// *this = d;
//}
// Just changed to return const vector&.
const std::vector<BYTE>& DEMO::Arr() const {
return m_array;
}
// Changed to use initializer list
DEMO::DEMO()
: m_array(1) {
// Old code: m_array = new BYTE[1];
}
// Doesn't need any code by us
DEMO::~DEMO() {
//if (m_array != 0)
// delete [] m_array;
}
i changed my code to use pointer to object instead of object for the value part in the map:
typedef map<unsigned int,DEMO*> t_mapType;
so i can assing as follow:
m_map[1] = new DEMO();
and i have to use a own free-mem method:
void DEMO::Clear() {
if (m_map.size() > 0) {
for (t_mapType::const_iterator it = m_map.begin(); it != m_mp.end(); ++it) {
if (it->second != 0)
delete it->second;
}
m_map.clear();
}
}
Related
I want to build my own full Vector class in C++. I started like this:
#include <iostream>
#include <initializer_list>
#define Print(x)(std::cout<< x << std::endl)
// Vector Class //
template <typename T>
class Vector
{
// Attributes
int length = 0;
T* array;
public:
// Default constructor
Vector()
: length(0), array(nullptr)
{ }
// Copy constructor
template<typename U>
Vector(const Vector<U>& other)
: Vector(other.len())
{
Print("Use Copy Constructor");
// Coppying other data to new array
array = new T[other.len()];
for (auto i=0; i < other.len(); i++)
array[i] = other[i];
}
// Move constructor
Vector(Vector<T>&& other)
: length(other.len()), array(other.array)
{
Print("Use Move Constructor");
// Deleting other array
other.length = 0;
other.array = nullptr;
}
// Constructor (does not allow uniform initialisation)
Vector(int length)
: length(length), array(new T[length])
{ }
// Constructor (with initialiser list and delegate constructor)
Vector(std::initializer_list<T> list)
: Vector((int)list.size())
{
std::uninitialized_copy(list.begin(), list.end(), array);
}
// Destructor
~Vector()
{
length = 0;
delete[] array;
array = nullptr;
}
// Function Len that returns the length
int len() const
{
return length;
}
// Operator[](int i) and its const overload
auto& operator[](int i)
{
return array[i];
}
auto& operator[](int i) const
{
return array[i];
}
// Copy assignment operator
template<typename U>
Vector& operator=(const Vector<U>& other)
{
Print("Use Copy Operator");
if (this != (Vector*)& other) {
/*
This works the same way but does not solve the problem:
Vector<typename std::common_type<T,U>::type> temp(other);
temp.swap(*this);
*/
delete[] array;
length = other.len();
array = new T[other.len()];
for (auto i = 0; i < other.len(); i++)
array[i] = other[i];
}
return *this;
}
// Move assignment opertator
Vector& operator=(Vector<T>&& other)
{
Print("Use Move Operator");
if (this != (Vector*)&other){
/*
This works the same way but does not solve the problem:
Vector<T> temp(std::move(other)); // moves the array
temp.swap(*this);
*/
delete[] array;
length = other.len();
array = other.array;
other.len() = 0;
other.array = nullptr;
}
return *this;
}
};
But if I now try to use the copy assignment operator like this:
Vector<double> double_vector = {3.4677, 3.212, 2.2, 6.3};
Vector<double> a = double_vector;
I get the following error message:
error: use of deleted function 'constexpr Vector<double>::Vector(const Vector<double>&)'
I assume that the problem lies within the copy constructor and copy assignment operator, but I sadly can't find a solution. What I find strange is that, if I comment out the move constructor and move assignment operator, the code does seem to work. This lets me think that the compiler has difficulty knowing which constructor to use. But I could also be very wrong about this.
Hope I gave enough info for an answer/push in the right direction.
A template is never a copy constructor, that is a converting constructor.
And as you have defined a bunch of other constructors, the otherwise default copy constructor will be defined as deleted.
This question already has answers here:
What is The Rule of Three?
(8 answers)
Closed 6 years ago.
I have a class
class Foo
{
public:
char* ptr;
Foo() { ptr=new char [10]; }
~Foo() { delete [] ptr; }
};
I have learnt that returning an object of this class is not possible as the dynamically allocated pointer is delete 'ed and creates a dangling pointer in the calling function
So how can I return An object of this class??
Foo Bar ()
{
Foo obj;
return obj;
}
Can it be solved by adding a copy constructor
Foo::Foo(const Foo& obj)
{
ptr = new char [10];
for( int i = 0 ; i < 10 ;++i )
ptr [i] = obj.ptr[i];
}
And the function as
Foo Bar ()
{
Foo obj;
return Foo(obj); //invokes copy constructor
}
Note These are just representation of the actual class I want and is not created according to recommended standards (ie. Please don't tell me to use std::string or std::vector).
So how can I return An object of this class??
You need to implement the copy constructor and the copy assignment operator that manage memory properly.
// Copy constructor
Foo(Foo const& copy) : ptr(new char[strlen(copy.ptr)+1])
{
strcpy(ptr, copy.ptr);
}
// Copy assignment operator
Foo& operator=(Foo const& rhs)
{
// Don't do anything for self assignment
if ( this != &rhs )
{
delete [] ptr;
ptr = new char[strlen(rhs.ptr)+1]);
strcpy(ptr, rhs.ptr);
}
return *this;
}
If ptr is always going to be an array of 10 chars, you'll need to rethink the copy constructor and copy assignment.
// Copy constructor
Foo(Foo const& copy) : ptr(new char[10])
{
memcpy(ptr, copy.ptr, 10);
}
// Copy assignment operator
Foo& operator=(Foo const& rhs)
{
// Don't do anything for self assignment
if ( this != &rhs )
{
memcpy(ptr, rhs.ptr, 10);
}
return *this;
}
I have write following demo code to learn copy constructor and assignment operator. However there is a little confuse. I was told to delete pointers in assignment operator and allocate new address to the data. However I can only make my code work delete that line. I have taken this page as a reference, but it only shows the example of int while not the int*. How can I solve this problem?
#include <iostream>
#include <string>
#include <vector>
#include <random>
#include <boost/smart_ptr.hpp>
#include <boost/make_shared.hpp>
using namespace boost;
class ClassOne
{
public:
ClassOne():data(NULL) {}
ClassOne(int data_param):data(NULL)
{
init(data_param);
std::cout << "construct" << std::endl;
}
virtual ~ClassOne()
{
if (data) {
delete data;
}
data = NULL;
}
ClassOne(const ClassOne& rhs){
std::cout<< "copy " <<std::endl;
data = NULL;
init(*rhs.data);
}
ClassOne& operator = (const ClassOne& rhs){
std::cout<< "assign " <<std::endl;
int* p_old = rhs.data;
data = new int(*p_old);
//delete p_old; // I have to delete this line to make my code work
return *this;
}
void init(int data_param)
{
if (data) {
delete data;
}
data = new int(data_param);
}
private:
int* data;
};
int main(int argc, const char * argv[]) {
ClassOne c1(10);
ClassOne c2(c1); // call copy constructor
ClassOne c3;
c3 = c1; // call assignment function
return 0;
}
You are trying to delete the other object's data member, when you are meant to delete your own (this) object's current data member instead. What you probably want is this:
ClassOne& operator = (const ClassOne& rhs){
std::cout<< "assign " <<std::endl;
delete data; // delete your own old data
data = new int(*rhs.data); // clone the rhs's data
return *this;
}
Your code fail because you are double deleting something: you delete the pointer in the copy assignment and in the destructor. Deleting a pointer don't make it null, that's why it passes the if in your destructor. (By the way, you don't need to check the pointer to be null before deleting it, delete does the check anyway)
I would recommend copy assignment to not alter the rhs variable, as deleting the data pointer can easily lead to memory access. I would rather implement a move constructor and assignment to make this behaviour explicit. I would remove copy constructor and assignment and add these function:
ClassOne(const ClassOne&) = delete;
ClassOne& operator=(const ClassOne&) = delete;
ClassOne(ClassOne&& rhs) {
std::swap(data, rhs.data);
}
ClassOne& operator=(ClassOne&& rhs) {
std::swap(data, rhs.data);
}
That would require std::move to be call on assignment.
Alternatively, you can implement a non-stealing copy constructor. That would require that youto deep copy the data pointer (copying the content instead of the pointer)
ClassOne(const ClassOne& rhs) {
if (!data) {
data = new int;
}
*data = *(rhs.data);
}
ClassOne& operator=(const ClassOne& rhs) {
if (!data) {
data = new int;
}
*data = *(rhs.data);
}
I can´t get the code to be vieved here for some unknown reason so I post my code with JavaScript snippets. Can anybody help me straighten this code out? I really need it to work and I am stuck. How can I write it so it works? I did put my code into JavaScript snippets but it´s not working. It is C++ code and i need a vector in a class.
class Bank {
public:
Bank(int m_size): konton(m_size, 0) {}
unsigned int getSize() const { return konton.size(); }
Bank(const Bank& _konton,) : konton(_konton){}
Bank(const Bank &rhs) : konton(rhs.konton) {}
Bank operator=(const Bank &rhs)
{
if (&rhs == this)
{
return *this;
}
konton = rhs.konton;
return *this;
}
void SetInfo(const int _konton)
{
konton = _konton;
}
int Konton() const { return konton; }
private:
vector<Bank> konton;
};
#endif
I cleaned a bit your mess and changed a bit metods, hope you gonna understand. But first of all take a look at rule of three/five/zero, because this code is mostly about it. Down below I pointed out some important things. It's not perfect, but should be got place to start.
class Bank {
public:
//
// Default constructor
// You don't need to define size of vector
Bank(): konton() {}
// Copy constructor
Bank(const Bank& other)
: konton(vector<int> (other.konton)) {
}
// Copy assignment operator
Bank operator=(const Bank &rhs)
{
if (&rhs == this) return *this;
konton = rhs.konton;
return *this;
}
// You missing destructor ~Bank();
//
// Also you can add two more functions:
// - Move constructor Bank(const Bank&& other);
// - Move assignment operator Bank& operator=(Bank&& other);
// This just add new element at the end of konton
void addKonto(const int _konto)
{
konton.push_back(_konto);
}
// And this remove last
void removeKonto()
{
konton.pop_back();
}
// Getters
vector<int> getKonton() const { return konton; }
unsigned int getSize() const { return konton.size(); }
private:
// I guess you mean to store accounts numbers in the Bank class
// To make it simple I made it int but, it can by any other your specific data type
vector<int> konton;
};
PS. Consider using IDE with on-the-fly syntax checking.
Edit: Here you have some more about this.
Below I have a class that keeps a reference count and a class that encapsulates a pointer to another object.
When class Ptr no longer has any objects attached to it, I want to deallocate. This entails deleting the object and the reference count. It is signaled when the value of ptrcnt hits zero.
My Ptr_count class has a destructor which does its part of the deallocation. I know that this destructor will get called when the destructor for Ptr gets called, and it will free up the memory accordingly. However, I'm not so sure it gets called when the assignment operator of Ptr gets called and the code if(--refptr == 0) { delete p; } gets executed.
There is a piece of code commented out in Ptr_count. If I use this instead of the destructor, the deallocation will occur any time the value of refptr goes to zero.
My question is, is there a way for the destructor to be called during the assignment operation in Ptr or would I need to use the code in Ptr_count that is commented out in order to get proper memory deallocation?
Obviously the destructor will be called when I exit the program and the memory will be freed one way or the other but while the program is running, I think that in that instance, the reference pointer can keep decrementing even after it hits zero and that memory will still be around.
class Ptr_count {
public:
Ptr_count() : ptrcnt(new size_t(1)) { }
~Ptr_count()
{
if(ptrcnt && *ptrcnt <= 0)
delete ptrcnt;
}
size_t operator++() const
{
++(*ptrcnt);
return *ptrcnt;
}
size_t operator--() const
{
--(*ptrcnt);
/*
if(*ptrcnt == 0) {
delete ptrcnt;
return 0;
}
*/
if(ptrcnt)
return *ptrcnt;
else
return 0;
}
operator bool() const
{
return ptrcnt;
}
size_t operator*() const
{
return *ptrcnt;
}
private:
size_t* ptrcnt;
};
template <class T> class Ptr {
public:
Ptr() : p(0) {}
Ptr(T* t) : p(t) {}
Ptr(const Ptr& h) : p(h.p), refptr(h.refptr) { ++refptr; }
Ptr& operator=(const Ptr& rhs)
{
++(rhs.refptr);
if(--refptr == 0) {
delete p;
}
refptr = rhs.refptr;
p = rhs.p;
return *this;
}
~Ptr()
{
if(--refptr == 0) {
delete p;
}
}
operator bool() const { return p; }
private:
T* p;
Ptr_count refptr;
};
EDIT::
Alternatively, if class Ptr_count had it's own assignment operator, would this be a work around to the problem? If I added the below code to Ptr_count, it seems like I may be able to free the memory when the reference count reaches 0 during assignment.
void operator=(const Ptr_count& rhs)
{
if(ptrcnt == 0)
delete ptrcnt;
ptrcnt = rhs.ptrcnt;
}
First of all, if this is for self-teaching only go on. Else stop what you are doing and start using std::shared_ptr / std::unique_ptr / std::weak_ptr or if you can't use C++11 std::auto_ptr.
Now to your code:
1) It would be safer and much more natural to increment your reference count in the copy constructor Ptr_count instead of the copy constructor of Ptr, since the purpose of Ptr_count class is to manage the reference count.
You can remove Ptr's copy constructor entirely after doing so.
2) There is an unnecessary check in the assignment operator of Ptr:
// Counter *must* be greater than 0 here, else p is 0 anyways.
Ptr& Ptr::operator=(const Ptr& rhs)
{
++(rhs.refptr); // Increment your counter to 2 or above.
if(--refptr == 0) { // Decrement your counter to 1 or above.
delete p; // Never get here.
}
refptr = rhs.refptr;
p = rhs.p;
return *this;
}
3) Your biggest problem is that you are overwriting refptr and p in the assignment operator.
Ptr& operator=(Ptr const& rhs)
{
Ptr temp(rhs);
std::swap(refptr, temp.refptr);
std::swap(p, temp.p);
return *this;
}
should fix that.
4) Your decrement operator of Ptr_count is somewhat broken.
size_t Ptr_count::operator--() const
{
--(*ptrcnt); // Access address stored in ptrcnt.
if(ptrcnt) // Test if address is valid.
return *ptrcnt;
else
return 0;
}
If ptrcnt was 0 when calling this method you get an access violation because of --(*ptrcnt). Anyway, this should not be necessary, simply remove it:
size_t Ptr_count::operator--() const
{
return --(*ptrcnt);
}
tl;dr
Because code says more than 1000 words, the complete code:
class Ptr_count {
public:
Ptr_count() : ptrcnt(new size_t(1)) { }
Ptr_count(Ptr_count const& rhs) : ptrcnt(rhs.ptrcnt) { ++(*this); }
~Ptr_count()
{
if(ptrcnt && *ptrcnt <= 0)
delete ptrcnt;
}
size_t operator++()
{
return ++(*ptrcnt);
}
size_t operator--()
{
return --(*ptrcnt);
}
operator bool() const
{
return ptrcnt;
}
size_t operator*() const
{
return *ptrcnt;
}
private:
size_t* ptrcnt;
};
template <class T> class Ptr {
public:
Ptr() : p(0) {}
Ptr(T* t) : p(t) {}
Ptr& operator=(Ptr const& rhs)
{
Ptr temp(rhs);
std::swap(refptr, temp.refptr);
std::swap(p, temp.p);
return *this;
}
~Ptr()
{
if(--refptr == 0)
delete p;
}
operator bool() const { return p; }
private:
T* p;
Ptr_count refptr;
};
I think your question primarily boils down to: does this assignment call the destructor of the counter?
refptr = rhs.refptr;
The answer is no. Personally, I would be inclined to actually not wrap the counter code into a separate class and rather have it done in the Ptr class directly. Also, I think my canonical way to implement the assignment operator would take care of the correct behavior:
Ptr& Ptr::operator(Ptr other) {
this->swap(other);
return *this;
}
void Ptr::swap(Ptr& other) {
std::swap(this->p, other.p);
this->ptrcnt.swap(other.ptrcnt);
}
void Ptr_count::swap(Ptr_count& other) {
std::swap(this->ptrcnt, other.ptrcnt);
}
That said, although a simple implementation of a reference counted pointer is a fun interview question, I strong recommend to never actually implement a reference counted pointer [unless you happen to also implement the rest of the standard C++ library] and just use std::shared_ptr<T>: apart from having worked out the nitty gritty details on how to manage the count, this class implements a couple of pretty cool features which go way beyond your simple reference counted pointer and many of these features actually happen to be needed in real code.