Which is a better practice for a reset function? - c++

Edit: MyClass is just an example. The question is actually about how to reset part of the members of a class. In my real case, the class is more complicated, and data would be as long as a million. Also, I have copy/move c'tors and operators, which are omitted in my example.
I have a class
class MyClass{
double *data;
int data_length;
MyClass() : data(nullptr), data_length(0){}
~MyClass(){
if(data != nullptr){
delete[] data;
}
}
}
Now I want to add a new member function reset().
Which of the following is a better practice?
(a)
MyClass::reset(double* in_data, int in_length){
if(data != nullptr){
delete[] data;
}
data = new double[in_length];
memcpy(data, in_data, in_length * sizeof(double));
data_length = in_length;
}
and
(b)
MyClass::reset(double* in_data, int in_length){
if(data != nullptr){
delete[] data;
}
data = in_data;
data_length = in_length;
}
It seems that (a) is safer, but it is more time consuming, and the clients of (a) have to manually delete temp in_data after calling reset(). (b) is more efficient, but it takes a risk that the client may delete in_data outside.

Just have a data member:
std::vector<double> data;
Then:
void reset(std::vector<double>&& new_data) { data = std::move(new_data); }
void reset(const std::vector<double>& new_data) { data = new_data; }
The first overload above will move data from an expiring vector<> if implicitly allowed or you explicitly grant permission in the calling code using std::move(), otherwise the second overload will copy:
myClass.reset(get_new_data_vector()); // moves returned vector
std::vector x = { ... };
myClass.reset(x); // do a full "deep" copy
myClass.reset(std::move(x)); // explicitly allow move from named local var
If you have other data collections, you can do something similar for each - each can be updated efficiently and independently.

It is better to copy the data and not depend on outside world for such stuff, especially when you have a destructor which deletes memory the class did not allocate.

Related

C++ - Should you delete allocated memory in the copy assignment operator of a class that uses raw pointers?

I am still somewhat new at c++, and I am a little confused about this.
Say we have struct struct_x that uses raw pointers as attributes. Should the raw pointers then be deleted in the copy assignment operator, when they are already allocated? Or should you just assign the new pointee to the pointer?
(I am aware that it is advised to use smart/unique/shared pointers).
Code example:
struct struct_x {
public:
// Some attributes.
char* m_arr nullptr;
size_t* m_len = nullptr;
size_t* m_alloc_len = nullptr;
// Default constructor.
struct_x() {
m_len = new size_t(0);
m_alloc_len = new size_t(0);
}
// Copy constructor.
// Treat "struct_x" as a unique pointer for this example.
struct_x(const struct_x& x) {
// Assign.
m_arr = new char[*x.m_alloc_len + 1];
memcpy(m_arr, x.m_arr,*x.m_len);
m_len = new size_t(*x.m_len);
m_alloc_len = new size_t(*x.m_alloc_len);
}
// Copy assignment operator.
void operator =(const struct_x& x) {
//
//
// OVER HERE
//
// Should the pointers be deleted when they are already allocated?
// Like:
if (m_arr != nullptr) { delete[] m_arr; }
if (m_len != nullptr) { delete m_len; }
if (m_alloc_len != nullptr) { delete m_alloc_len; }
// Or not?
// Assign.
...
}
}
Second question:
Do I need to delete the old m_arr after using memmove?
// Resize.
void resize(const len_t& req_len) {
using T = char; // only for this example.
if (req_len > m_alloc_len) {
if (m_alloc_len == 0) { m_alloc_len = req_len; }
m_alloc_len *= 16;
T* l_arr = new T [m_alloc_len + 1];
memmove(l_arr, m_arr, m_len);
// if (m_arr != nullptr && m_arr) { delete [] m_arr; } // Do i need to delete here, no right?
m_arr = l_arr;
}
}
If you are implementing a string-like class as an exercise, then m_len and m_alloc_len should not be pointers at all. Only m_arr should be a pointer. If you are not doing an exercise, you should be using std::string or perhaps std::vector<char>.
Having said that...
It is perfectly fine and necessary to delete owning raw pointers in assignment operators of resource-managing classes.
There is a caveat though. The assignment operator should be protected against self-assignment. If you do
my_object = my_object;
then without such protection your program will access deleted memory area. You want this:
void operator =(const struct_x& x) {
if (this != &x) {
// contents of your assignment operator
}
}
my_object = my_object is an unlikely assignment to appear in a program, but such things can and do happen, especially if there is indirection involved. Say when doing a[i] = a[j], it is perfectly reasonable to have i == j.
There are other (better) ways to protect against self-assignment. You will encounter them in due course. You probably need to learn about move semantics first.before

Copy constructor with pointers fails when returned by a function

I am a new user here and this is my first question, so please don't judge me hard. I cheked many similar questiontions like this not only on this site, also on others too. But I didn't find the answer.
The problem is to create copy constructor with pointers. For those people who may ask: why do you need pointers?: I have a class stmt, which contains vector<stmt>, it will allow me to construct tree-like data structure. Then I will perform some functions to change values of stmt's parameters. Without pointers they won't change
It compiles, but then gives Exception Unhandled (Runtime error)
My first attemp looks like this:
struct stmt
{
string lexeme;
int *size;
int *lay;
bool *nl;
vector<stmt>* follow;
stmt(string l)
{
lexeme = l;
size = new int;
*size = l.size()+2;
lay = new int;
*lay = 0;
nl = new bool;
*nl = false;
follow = new vector<stmt>;
}
stmt(const stmt &s)
{
lexeme = s.lexeme;
size = new int; //Crashes here : Unhandled exception:std::length_error at memory location ...
*size = *s.size;
lay = new int;
nl = new bool;
follow = new vector<stmt>;
follow = s.follow;
}
};
Second time I tried also this:
stmt(const stmt &s)
:lexeme.(s.lexeme), size (s.size), ......and so on
{}
Unfortunately, this also doesn't help.
So, this is my third attemp but didn't help
IMPORTANT: I noticed that it happens when I am trying to create and emplace_back new stmt element in a vector of another stmt using functions which return type is stmt.
Here is a code which represents the key problem:
stmt Program("Program");
stmt ParseRelop(string p);
void EMP(stmt s)
{
s.follow->push_back(ParseRelop("token"));
}
stmt ParseRelop(string p)
{
stmt s(p);
return s;
}
int main()
{
EMP(Program);
cout<<Program.follow->at(0).lexeme;
}
Like this
stmt(const stmt &s)
{
...
follow = new vector<stmt>(*s.follow);
}
This version allocates a new vector by copying the vector from the copied object (*s.follow is the vector in the copied object).
Your version allocated a new pointer but then overwrote it with a copy of the pointer from the copied object.
You want to copy the vector, not the pointer that's pointing at the vector.
You should use the same technique for your other pointers
size = new int(*s.size);
lay = new int(*s.lay);
etc.
Let's start by making your stmt class copy correct. Once you do that, then the issues will come from other parts of your code that do not involve stmt leaking memory, or accessing invalid memory:
#include <vector>
#include <string>
#include <algorithm>
struct stmt
{
std::string lexeme;
int *size;
int *lay;
bool *nl;
std::vector<stmt>* follow;
// Constructor. Note the usage of the member initialization list
stmt(std::string l) : lexeme(l), size(new int), lay(new int(0)), nl(new bool(false)),
follow(new std::vector<stmt>())
{
*size = l.size() + 2;
}
// Copy constructor. Note that we use the member initialization list,
// and copy all the members from s to the current object, not partial copies
stmt(const stmt &s) : lexeme(s.lexeme), size(new int(*s.size)), nl(new bool(*s.nl)),
lay(new int(*s.lay)), follow(new std::vector<stmt>(*s.follow))
{}
// The assignment operator. Note that we use copy / swap to swap out
// all the members, and that a check for self-assignment is done.
stmt& operator=(const stmt &s)
{
if (this != &s)
{
stmt temp(s);
std::swap(lexeme, temp.lexeme);
std::swap(size, temp.size);
std::swap(lay, temp.lay);
std::swap(nl, temp.nl);
std::swap(follow, temp.follow);
}
return *this;
}
// The destructor destroys all the memory
~stmt()
{
delete size;
delete lay;
delete nl;
delete follow;
}
};
This class now follows the rule of 3 properly, and should be safely copyable. I put in the comments what each function does, and you should research on why the class should work correctly now.
I didn't want to go too much in depth, because in reality you wouldn't have pointers to int, bool or even vector<stmt>.
References:
Rule of 3
Copy / Swap Idiom

Different Destructor Types?

I have an object called a Chunk that holds a pointer to a b2Body. It does other important things, but i removed those for simplicity. Heads up, smart pointers won't work(I think), you'll see why.
class DChunk
{
public:
DChunk();
DChunk(const DChunk& old);
virtual ~DChunk();
virtual b2Body* getBody() const;
private:
b2Body* m_pBody;//pointer;
};
The question is, how to define when to delete the m_pBody object.
If I want to copy this object, like say there is a vector of these things and I push_back another, it will call the Copy Constructor, copy the memory address of m_pBody(thats what i want), and then delete the old one. If the Destructor on this object deletes m_pBody, that's obviously bad, because the new copy wont have a valid memory address, but if it doesn't delete it, then m_pBody will never be deleted, and it needs to be deleted when there are no more Chunks pointing at it.
The only correct way to delete the m_pBody object is to call m_pBody->GetWorld()->DestroyBody( m_pBody ); and thats not under my control, so smart pointers dont really work.
I was hoping there would be different types of destructors that get called appropriately, like when a copy has been made in a vector. Also, there should never be more than one Chunk associated with one b2Body, if that is helpful.
I will assume you have something like
vector<DChunck> myvec;
and you are worried about doing
obj=DChunk()
myvec.push_back(obj)
First of all (this is very beginner friendly approach, avoiding smart pointers or any C++11) there's something not quite correct about creating a container DChunk objects. That's because when you declare
vector<DChunk>
you are telling your vector that it will receive objects the size of DChunk.
However, since that class contains a pointer to an array, m_pBody (array's size will not be constant!), this approach will not be too "healthy" for C++.
Given this, you can do something else, sticking to your class design: create a container of pointers!
You can create
vector<DChunk*> myvec;
and if you want to add an object to that vector, you just do
DChunk *obj = new DChunk();
myvec.push_back(event);
since now the container is handling pointers, which can be juggled around without interfering with the objects content, avoiding the worries concerning a destructor.
Calling an object's method will now be, for example,
(*myvec[3]).getBody()
or (cleaner version)
myvec[3]->getBody()
Hope I addressed your question
You can also provide move constructor so that instead of copying, it would move stuff... Here's an example that I made some hours ago, because I had the same problem (I didn't know in what order would these constructors and when be called, also "&&" is move constructor):
A move constructor is similar to copy constructor. The difference is that in move constructor instead of copying values and stuff, you assign given object's pointers (not copy) and values to a new one (this->temp = OldClass.temp) and then make OldClass.temp = NULL; so that when the unavoidable destructor is called, it finds a NULL pointer and does not delete it.
#include <iostream>
#include <Windows.h>
class MyClass
{
public:
MyClass()
{
temp = new RECT();
ZeroMemory(temp, sizeof(RECT));
}
MyClass(int x, int y)
{
temp = new RECT();
ZeroMemory(temp, sizeof(RECT));
temp->left = x;
temp->top = y;
}
MyClass(MyClass &&OldClass)
{
if (this->temp != NULL)
{
delete this->temp;
this->temp = NULL;
}
temp = OldClass.temp;
OldClass.temp = NULL;
}
MyClass& operator=(MyClass &&OldClass)
{
if (this->temp != NULL)
{
delete this->temp;
this->temp = NULL;
}
temp = OldClass.temp;
OldClass.temp = NULL;
return *this;
}
MyClass(const MyClass &OldClass)
{
*temp = *OldClass.temp;
}
MyClass& operator=(const MyClass &OldClass)
{
*temp = *OldClass.temp;
return *this;
}
~MyClass()
{
if (this->temp != NULL)
{
delete this->temp;
this->temp = NULL;
}
}
void Print()
{
std::cout << temp << " " << temp->left << " " << temp->top << " " << temp->right << " " << temp->bottom << '\n';
}
private:
RECT *temp;
};
int main()
{
MyClass bla, cha(54, 48);
bla.Print();
cha.Print();
bla = MyClass(2, 2);
bla.Print();
bla = cha;
bla.Print();
cha = MyClass(54, 2);
cha.Print();
std::cin.get();
return 0;
}
In common, a proper memory management is non trivial task and no universal decision are existing. Some simple and common well-known methods are presented as "smart pointer" types in newest libraries (and you can also define them yourself (by copy known "standard definition")). But it also is not an completely universal :-)
And your question seems to be a question for a such universal solution.
Some other programming languages (java ... , not C++) advertise you to get rid of that problem (by the built-in methods of language implementations).
You write: "Also, there should never be more than one Chunk associated with one b2Body, if that is helpful." . And then the problem seems to disappear (because the Chunk cannot be copied at all). (?)

Swapping an object within itself

I'm trying to swap an object within itself. It works but when I add a destructor it gives me a double free error. Is there a way to prevent this? The method I'm talking about is void swap(SimpleArray &object).
(Sorry if you read this before I had the wrong info in my post...)
#include "TestType.h"
class SimpleArray {
private:
TestType* pArray;
//TestType* temp;
public:
SimpleArray(TestType *array)
{
this->pArray = array;
}
~SimpleArray() { delete[] pArray; }
SimpleArray() { pArray = 0;}
SimpleArray(const SimpleArray& arg){ pArray = arg.pArray; }
~SimpleArray() { delete[] pArray; }
TestType * get() const{ return pArray; }
bool isNonNull() const { return pArray != 0; }
//TestType* pArray;
void reset(TestType*& p) {this->pArray = p; }
void reset() { pArray = 0; }
void swap(SimpleArray &object) { SimpleArray temp; temp = object; object = *this; *this = temp;}
TestType * release() { pArray = 0; return pArray; }
TestType& getReference(int a) { return *pArray; }
};
This works but once I add the destructor it gives me a "double free or corruption error". How do I solve this? Here's the function in main where it messes up.
bool testGetReleaseSwap() {
SimpleArray array1;
if (array1.get() != 0)
return false;
TestType* directArray1 = new TestType[100];
array1.reset(directArray1);
if (array1.get() != directArray1)
return false;
TestType* directArray2 = new TestType[50];
SimpleArray array2(directArray2);
array1.swap(array2);
if (array1.get() != directArray2 || array2.get() != directArray1)
return false;
array2.swap(array1);
if (array1.get() != directArray1 || array2.get() != directArray2)
return false;
array1.swap(array1);
if (array1.get() != directArray1)
return false;
if (array1.release() != directArray1 || array2.release() != directArray2)
return false;
if (array1.get() != 0 || array2.get() != 0)
return false;
delete[] directArray1;
delete[] directArray2;
return true;
}
The trivial way out here is to invoke temp.release() at the end if your swap method to prevent double deletion.
The underlying issue is much deeper, though. In C++ it is crucial to always maintain strict semantics of who owns something, for example a memory region that requires deletion.
A frequent pattern is that the object that allocates something is also responsible for cleaning up and no one else. This fits nicely with SimpleArray, but the copy constructor breaks it because it multiplies the number of owners!
To implement shared data semantics you have to invest more work (reference counting etc.) or you have to forbid array copying and make the copy constructor private.
A clean way to fix up swap to work without copying the object would be:
void swap(SimpleArray &object) {
TestType* temp = object.pArray;
object.pArray = this->pArray;
this->pArray = temp;
}
(std::swap(object.pArray, pArray); works as well)
Because to swap the memory regions of the array fits nicely with a single-owner pattern, what went wrong here is only the use of the full object copy.
You should read up on resource management and ownership semantics in C++. Your code will always be error prone unless you absolutely know who owns what.
It seems to me that you are trying to implement a class that has shallow copy semantics (and possibly copy-on-write). To do that successfully you need to track how many other owners of the shared data are still around and need to destroy the owned object, when that count reaches zero. You can either use a std::shared_ptr for that or implement the reference counting yourself.
As for the real problem in that specific example, look at what you copy constructor is doing. It is not copying but simply taking another reference (a pointer to be specific) to the object that is already owned by its argument. That by itself already enough to get a double free and your swap testcase is simply exposing that issue.

How to implement copy operator for such C++ structure?

So having
struct ResultStructure
{
ResultStructure(const ResultStructure& other)
{
// copy code in here ? using memcpy ? how???
}
ResultStructure& operator=(const ResultStructure& other)
{
if (this != &other) {
// copy code in here ?
}
return *this
}
int length;
char* ptr;
};
How to implement "copy constructor" and "assignment operator"? (sorry - I am C++ nube)
Update: sbi and others ask - why do I want to manually deal with raw memory? My answer is simple - In a students project I am part of now we use lots of C library's such as for example OpenCV OpenAL and FFmpeg and there are more to come. Currently using C++ we try to create a graph based direct show like cross platform library that would be helpful in live video broadcasting and processing. Our graph elements currently use char* and int pairs for data exchange. To cast data to subscribed elements we use raw memcpy now. I want to go further and make it possible for us to make our graph elements base C++ template. So that one graph element would be capable of of sharing current graph element data with other Graph elements and that data it shares would be a structure that would contain not one char* one int but any number of data fields and nearly any elements inside. So that is why I need to understand how to create a basic C++ structure that implements "copy constructor" and "assignment operator" for me to be capable to use new for us data casting algorithms like
void CastData(T item){
for(size_t i = 0 ; i < FuncVec.size(); i++){
T dataCopy = item;
FuncVec[i](dataCopy);
}
}
instead of currently used
void CastData(char * data, int length){
for(size_t i = 0 ; i < FuncVec.size(); i++){
char* dataCopy = new char[length];
memcpy(dataCopy, data, length);
FuncVec[i](dataCopy, length);
delete[] dataCopy;
}
}
You might want to explain why you want to manually deal with raw memory. I haven't done this in a long time, it's what std::string and std::vector where designed for:
struct ResultStructure
{
// nothing else needed
std::string data; // or std::vector<char>
};
But if you really need to do this the hard way (is this homework?), then be advised that it is, at first, surprisingly hard to get this right. For example, a naive implementation of the assignment operator might be like this:
// DON'T TRY THIS AT HOME!!
ResultStructure& ResultStructure::operator=(const ResultStructure& rhs)
{
delete[] ptr; // free old ressource
ptr = new char[rhs.length]; // allocate new resourse
std::copy(rhs.ptr, rhs.ptr+rhs.length, ptr; // copy data
length = rhs.length;
}
If someone accidentally assigns an object to itself (which might happen if all you have is two references and you don't suspect them to refer to the same object), then this will fail fatally.
Also, what if new throws an exception? (It might throw std::bad_alloc if memory is exhausted.) Then we have already deleted the old data and have not allocated new data. The pointer, however, still points at where the old data used to be (actually, I think this is implementation-defined, but I have yet to see an implementation that changes a ptr upon deletion), and the class' destructor (you knew that class would need a destructor, right?) would then attempt to delete a piece of data at an address where no data is allocated. That's Undefined Behavior. The best you can hope for is that it crashes immediately.
The easiest way to do this is to employ the Copy-And-Swap idiom:
struct ResultStructure
{
ResultStructure(const ResultStructure& other)
: ptr(new char[rhs.length]), length(rhs.length)
{
std::copy(rhs.ptr, rhs.ptr+rhs.length, ptr);
}
~ResultStructure() // your class needs this
{
delete[] ptr;
}
ResultStructure& operator=(ResultStructure rhs) // note: passed by copy
{
this->swap(rhs);
return *this
}
void swap(const ResultStruct& rhs)
{
using std::swap;
swap(length, rhs.length);
swap(ptr, rhs.ptr);
}
std::size_t length;
char* ptr;
};
Note that I have added a destructor, changed the assignment operator to pass the argument per copy (we need the copy constructor invoked to allocate memory), and added a swap member function. Per convention a swap() function never throws and is fast, preferably O(1).
I know that GMan's discussion of the Copy-And-Swap idiom is exhaustive enough to be and exhausting while mine is probably too terse for you, and you will likely not understand a lot of it at first, but try to persevere and to understand as much as possible.
If you use std::string, instead of char*, you would not even need to write operator= or copy-constructor. The compiler generated code would do your job very well.
But as a general solution (for some other scenario), use copy-and-swap idiom:
Copy-and-Swap Idiom
What is the copy-and-swap idiom?
Exceptional C++ by Herb Sutter has described these in great detail. I would recommend you to read items from this book. For the time being, you can read this article online:
Exception-Safe Generic Containers
The easy solution is to use a std::string instead of char* member.
Then the compiler-generated copy constructor and copy assignment operator just work.
As a rule, and especially as a novice, don't have raw pointer members.
Cheers & hth.,
As has been said, and as was recommending in the question this emanated from, you should probably reuse an existing container. At least the code would be right :)
For educational purposes though, let's examine this structure:
class Result
{
public:
private:
size_t length; // can't really be negative, right ?
char* data;
};
Here, we need explicit memory management. This implies, notably, following the Rule Of Three (say thanks to Fred)
Let's begin with actually building our object:
Result::Result(): length(0), data(0) {}
Result::Result(size_t l, char* d): length(0), data(0)
{
if (!d) { return; }
data = new char[l]; // this may throw, so we do it first
length = l;
memcpy(data, d, l);
}
Now we can implement the traditional operators:
// Swap
void Result::swap(Result& other)
{
using std::swap;
swap(length, other.length);
swap(data, other.data);
}
// Copy Constructor
Result::Result(Result const& other): length(0), data(0)
{
if (!other.length) { return; }
data = new char[other.length];
length = other.length;
mempcy(data, other.data, length);
}
// Assignemt Operator
Result& Result::operator=(Result other)
{
this->swap(other);
return *this;
}
// !IMPORTANT!
// Destructor
Result::~Result()
{
delete[] data; // use the array form of delete
// no need to test for nullity, it's handled
}
this is std::vector<char>'s job - or is this homework?
the vector would replace both length and the allocation behind ptr. the vector is the c++ idiom, and you'll not make friends with other c++ devs if you implement your classes like you've described. of course, there are corner cases, but standard containers such as vector are the default.
the vector knows how to copy chars as well as itself, and the implementations are optimized and tested.
here's how to explicitly implement copy ctor/assign using a vector:
struct ResultStructure {
ResultStructure(const ResultStructure& other) : d_chars(other.d_chars) {
}
ResultStructure& operator=(const ResultStructure& other) {
if (this != &other) {
this->d_chars = other.d_chars;
}
return *this;
}
std::vector<char> d_chars;
};
I think this should do the work:
struct ResultStructure
{
ResultStructure(const ResultStructure& other);
ResultStructure& operator=(const ResultStructure& other);
int length;
char* ptr;
};
ResultStructure::ResultStructure(const ResultStructure& other):length(other.length)
{
ptr = (char*)malloc(length);
memcpy(ptr, other.ptr, length);
}
ResultStructure& ResultStructure::operator=(const ResultStructure& other)
{
length = other.length;
ptr = (char*)malloc(length);
memcpy(ptr, other.ptr, length);
return *this;
}
Please remember about freeing ptr in destructor.
What is stored under ptr? If text, why not to use std::string? Anyway you can use std::vector. The constructors will be much easier then...
How is the memory to which ptr points allocated?
if using new, allocate with new, set length and then copy
other.length = length;
other.ptr = new char[length];
memcpy( other.ptr, ptr, length );
If you're allocating the memory with malloc, substitute a call to malloc in place of the call to new. If you're using some other memory scheme, figure it out. :)