Return value to class object in C++ - c++

I have a header file:
using namespace std;
class IntList{
private:
int *Intl;
int Capacity;
int Count;
public:
IntList(int capacity){
Capacity = capacity;
Count = 0;
Intl = new int[capacity];
}
~IntList(){
delete Intl;
}
//adds the integers of the specified collection to the end of the List; return false if the new Count will be greater than Capacity
bool AddRange(const IntList &items){
//int *Temp = items.;
if(items.Count > Capacity - Count){
return false;
}else{
for(int i = 0; i <items.Count; i++){
Intl[Count] = items.Intl[i];
Count++;
}
return true;
}
}
};
But I don't know why I can't return value to IntList object in there:
//creates a copy of a range of elements in the source List
IntList GetRange(int index, int count){
IntList A(count);
for(int i = 0; i < count; i++){
A.Intl[i] = Intl[index -1 +i];
}
return A;
}
I want to return value of A whose type is IntList but I meet an error on "_BLOCK_TYPE_IS_VALID(pHead->nBlockUse) in visual studio 2010. How can I repair it?

Because int *Intl; is an object you manually manage, you'll need to implement the copy constructor for your class.
The function GetRange returns by value. The local object A gets destroyed, and its member Intl gets deleted in the destructor, so your copy (as copied by the default copy constructor) is only a shallow one, and will contain an invalid member.
EDIT: As Rob correctly pointed out, you'll also need to implement the assignment operator (you already have a destructor).

For an object which is returned by value makes a call to copy-constructor . You must make a copy-constructor and define it so that you get appropriate results. Returning by reference actually does not require call to copy constructor but should not be made for a temporary object. Also since you have a pointer type as member variable in class . It would be appropiate for you to overload the = operator. It should be define properly to avoid memory leak. Do something like this Intlist a=GetRange(index,count) . Also you should create a copy constructor for this . Your code also has a bug that it doesnot overload= operator for class Intlist .
you can write a copy constructor something like this :-
Intlist::Intlist(const Intlist& cSource)
{
capacity = cSource.capacity;
count= cSource.count;
// Intl is a pointer, so we need to deep copy it if it is non-null
if (cSource.Intl)
{
// allocate memory for our copy
Intl = new int[capacity];
// Copy the Intl into our newly allocated memory in for loop
for(i=0;i<capacity;i++)
{
// copy part
}
}
else
intl = NULL;
}
Just an e.g how you should write it.

Related

C++ value initialize items of a custom container

Lets take custom vector implementation as an example:
template<typename Object>
class myVector {
public:
explicit myVector(int size = 0) :
_size{ size },
_capasity{ size + SPARE_CAPACITY }
{
_buff = new Object[_capasity];
if (_size > 0) {
for (int i = 0; i < _size; i++) {
//_buff[i] = 0;
}
}
}
// more code
private:
Object * _buff = nullptr;
int _size;
int _capasity;
};
So my question is, how to make myVector be value-initialized in case I'll initialize it as:
int main() {
myVector<int> v02(5);
}
Here, it contains 5 int values, so I need it to be all zeros; same with other types. I commented out _buff[i] = 0; as it's specific to int. Please give me some hints.
It's as simple as
for (int i = 0; i < _size; i++)
_buff[i] = Object{};
Alternatively, you could get rid of the loop and add a pair of {} (or ()) here:
_buff = new Object[_capasity]{};
// ^^
But this option would value-initialize all _capasity objects, rather than the first _size ones, as noted by #bipll.
Also, note that if you want to mimic the behavior of std::vector, you need to allocate raw storate (probably std::aligned_storage) and call constructors (via placement-new) and destructors manually.
If Object is a class type, _buff = new Object[_capasity]; calls default constructors for all _capasity objects, rather than for the first _size objects as std::vector does.
Note that when calling
_buff = new Object[_capasity];
(btw, why have you moved this initialization out of init-list, into constructor body?) you already have default-initialized _capasity objects. Default initialization has the following effects here: while elements of scalar type would remain uninitialized (and reading from them UB), for class types you have already called _capasity constructors.
To avoid unnecessary constructions you have the following possible options, among others:
Use std::aligned_alloc to allocate non-initialized memory:
explicit myVector(std::size_t size = 0) :
size_{ size }
, capacity_{ size + SPARE_CAPACITY }
, buff_{std::aligned_alloc(alignof(Object), _capacity)}
{
if(!buff_) throw std::bad_alloc();
if(size) new (buff_) Object[size]{}; // empty braces answer your original query
}
Remember that again buff_ should be aligned_alloced when vector grows (can be std::realloc()ed for trivial types), and in destructor it should be std::free()d — and prior to that size_ objects inside it should be destructed (with an explicit call to ~Object()).
Change buff_'s type to something more trivial yet properly aligned:
using Storage = std::aligned_storage_t<sizeof(Object), alignof(Object)>;
Storage *buff_;
Object *data_ = nullptr;
public:
explicit myVector(std::size_t size = 0) :
size_{ size }
, capacity_{ size + SPARE_CAPACITY }
, buff_{new Storage(_capacity)}
{
if(size) data_ = new (buff_) Object[size]{};
}
Again, in destructor, objects should be manually destroyed, but this time buff_ can be simply delete[]d afterwards.

2d array memory management issue

I have to write a code that gets a string and turns it into an object of a class. Everything is working as expected but I'm unable to deallocate the dynamically allocated 2d array of objects.
I know the issue is within the destructor and the Move assignment operator for the object, I keep getting SIGBRT and EXC_BAD_ACCESS errors when I try to run it.
Below is my Code for the constructor, destructor and move assignment/constructor
//CustomerOrder.cpp
CustomerOrder::CustomerOrder(std::string&
src):Name(src),Product(),ItemCount(),ItemList(),field_width(){
std::vector<ItemInfo> info;
std::string* tokens[] = { &Name, &Product };
Utilities utils;
size_t next_pos = -1;
bool more = true;
for (auto& i : tokens) {
if (!more) break;
*i = utils.extractToken(src, next_pos, more);
}
while (more){
info.push_back(utils.extractToken(src, next_pos, more));
}
if(!info.empty() && info.back().ItemName.empty()){
info.pop_back();
}
ItemCount = info.size();
ItemList = new ItemInfo*[ItemCount];
for (int i = 0; i < ItemCount; i++){
ItemList[i] = new ItemInfo(info.at(i).ItemName);
}
if (utils.getFieldWidth() > field_width){
field_width = utils.getFieldWidth();
}
}
CustomerOrder::~CustomerOrder(){
for(int i = 0; i<ItemCount;i++){
delete[] ItemList[i];
}
delete[] ItemList;
}
CustomerOrder::CustomerOrder(CustomerOrder&& src){
*this = std::move(src);
}
CustomerOrder& CustomerOrder::operator=(CustomerOrder&& src){
if(this!= &src){
delete [] ItemList;
Name = std::move(src.Name);
Product = std::move(src.Product);
ItemCount = std::move(src.ItemCount);
ItemList = std::move(src.ItemList);
src.ItemList = nullptr;
}
return *this;
}
And the ItemInfo struct
//ItemInfo struct
struct ItemInfo
{
std::string ItemName;
unsigned int SerialNumber;
bool FillState;
ItemInfo(std::string src) : ItemName(src), SerialNumber(0),
FillState(false) {};
};
You are combining "new" with "delete[]". If you use "new" use "delete" if you use "new[]" then use "delete[]" for the thing.
This is your problem there: "delete[] ItemList[i];" it should be "delete ItemList[i];" instead
This line of your code ItemList[i] = new ItemInfo(info.at(i).ItemName); doesn't allocate a dynamic array, yet this code in your destructor tries to delete it as thought it was a dynamic array.
for(int i = 0; i<ItemCount;i++){
delete[] ItemList[i];
}
A quick fix would to be to change delete[] to delete. However, it appears as though it would be much easier to simply allocate a single dynamic array. In other words, allocate ItemList as such ItemList = new ItemInfo[ItemCount]; Granted, you would have to change the type, but it makes more sense from what you posted.
Another possible issue is that in your destructor you don't check if the ItemList is a nullptr or actually allocated to anything. To which, your destructor could possibly try to access invalid data. Not only that, but your move operator deletes the ItemList without deleting the data inside of it.
You could make a function to free up the data in ItemList and then call that function from the destructor and move operator.
On a side note, why are you using dynamic 2D arrays when it appears that you know how to use vectors? A vector would handle all of this in a much simpler fashion. For example, the type would be std::vector<std::vector<ItemInfo>>.

Copying an array from a struct which is senе through a function

I have want to send a struct to json->setInformation but my program crashes when i try to copy the array which is inside the struct. The rest of the data is okay its just the array which makes the crash occur.
info = data->getInformation();
json->setInformation(info);
getInformation returns a struct which i can read in main.cpp
when i try to send this struct to setInformation it crashes...
information.h which holds my struct
struct information{
String location;
String protocol;
uint8_t groupID;
uint8_t* data;
information& operator=(const struct information& that){
location = that.location;
protocol = that.protocol;
groupID = that.groupID;
for (int i = 0; i < 9; ++i){
data[i] = that.data[i];
}
return *this;
}
};
json.cpp
void JSON::setInformation(information data){
info->location = data.location;
info->protocol = data.protocol;
info->groupID = data.groupID;
// for (int i = 0; i < 9; ++i){
// info->data[i] = data.data[i];
// }
// Serial.print("after JSON: ");
// Serial.println(info->data[0]);
}
this code works fine but when i uncomment the for lop which should copy the array it crashes
Did you allocate memory for your uint8_t data* parameter before using it ?
Then remember to deallocate memory when you don't need it anymore, thus avoiding memory leaks.
Your object is passed by copy to the function, but you have no copy constructor.
Default copy constructor will not copy you raw pointer correctly. So either you declare and implement a copy constructor, either you replace your raw pointer (uint8_t*) by a vector (std::vector<uint8_t>) which is safely copyiable (then copying the object will become a valid operation).
Moreover, we can't see who's allocating/deallocating your raw pointer, but I suspect you are missing a destructor function too.
Your code breaks the rule of three which is the minimal requirement for any class you'll declare in C++.

Problems with C++ Class Template Initialization

Can someone explain to me why...
DataStructure<MyClass> ds;
cin >> size;
ds = DataStructure<MyClass>(size);
causes my program to crash, but...
cin >> size;
DataStructure<MyClass> ds = DataStructure<MyClass>(size);
does not?
I think it has something to do with my program using the default constructor and followed by an attempt to use the implicit copy constructor but I am not sure.
To give more context, I'm creating a hash table class and in the default constructor, I initialize the array with data to nullptr and in the constructor with the size argument, I create the array with the data to new T * [size] and set each element to nullptr.
Constructor without any parameters:
this->data = nullptr;
vs.
Constructor with size parameter:
this->data= new T * [size];
for(int i = 0; i< size; i++)
{
data[i] = nullptr;
}
You will need to declare a copy constructor. If you do not have a copy constructor then all members will be copied. In your case data will point to the data reserved in the second class. Next, this data will be destroyed together with the class and points to nothing. That will most likely cause your program to crash.
Your copy constructor should do deep copy, something like this:
DataStructure(const DataStructure &rhs)
{
if (this->data) delete[] data;
this->data = new T*[rhs.GetSize()];
for (int i=0; i<rhs.GetSize(); i++)
{
this->data[i] = rhs.data[i];
}
return *this;
}

Assignment overloading: why does using the same object cause problems in the program?

Suppose we have the following:
class StringClass
{
public:
...
void someProcessing( );
...
StringClass& operator=(const StringClass& rtSide);
...
private:
char *a;//Dynamic array for characters in the string
int capacity;//size of dynamic array a
int length;//Number of characters in a
};
StringClass& StringClass::operator=(const StringClass& rtSide)
{
capacity = rtSide.capacity;
length = rtSide.length;
delete [] a;
a = new char[capacity];
for (int i = 0; i < length; i++)
a[i] = rtSide.a[i];
return *this;
}
My question is: why does this implementation of overloading the assignment operator cause problems when we try to assign an object to itself like:
StringClass s;
s = s;
The textbook I'm reading (Absolute C++) says that after delete [] a; "The pointer s.a is then undefined. The assignment operator has corrupted the object s and this run of the program is probably ruined."
Why has the operator corrupted s? If we're reinitalizing s.a right after we delete it, why does this cause such a problem in the program that we have to redefine the function as:
StringClass& StringClass::operator=(const StringClass& rtSide)
{
if (this == &rtSide)
//if the right side is the same as the left side
{
return *this;
}
else
{
capacity = rtSide.capacity;
length = rtSide.length;
delete [] a;
a = new char[capacity];
for (int i = 0; i < length; i++)
a[i] = rtSide.a[i];
return *this;
}
}
If you are assigning an object to itself both a and rt.a point to the same string, so when you do delete [] a you are deleting both what a and rt.a point to; then you do reallocate it, but the data you were going to copy (on itself) in the loop has been lost in the delete.
In the loop now you will just copy whatever junk happens to be in the memory returned by new on itself.
By the way, even with the "safety net" of the self-assignment check that assignment operator isn't completely ok (for instance, it's not exception safe); the "safe" way to define the "big three" (copy constructor, assignment operator, destructor) is using the "copy and swap idiom".
If you self-assign, you free (delete) the string via the LHS argument before you copy it to the newly allocated space via the RHS argument. This is not a recipe for happiness; it is undefined behaviour and anything may happen. A crash is plausible; if you're really unlucky, it may appear to work.
Consider what the value of rtSide.a is when you're inside the broken operator=.
It's the same as this->a, the values you just clobbered. Accessing non-owned memory is undefined behavior, thus accessing this->a is undefined behavior (since you just freed it).
delete [] a;
a = new char[capacity];
for (int i = 0; i < length; i++)
a[i] = rtSide.a[i]; //Invalid when this->a == rtSide.a
//because rtSide.a is no longer owned by your program.
If you did actually want to do this, you would have to make a copy of a before deleting it:
char* ca;
if (this == &rtSide) {
ca = copy of rtSide.a or this->a;
} else {
ca = rtSide.a;
}
//Do your assigning and whatnot
if (this == &rtSide) {
delete[] ca;
}
Obviously it's much more efficient to just do nothing instead of making temporary copies of all of an instances own members. It's the same concept as doing int x = 5; int y = x; x = y;
It is because you've first deleted the pointer delete [] a;
and then later on trying to copy from the deleted location:
for (int i = 0; i < length; i++)
a[i] = rtSide.a[i]; //rtSide has already been deleted as 'this' and '&rtSide' are same.
Remember it is the same location you are trying to copy from, which you've already deleted.
Hence, the error!
The later code you posted fixes this problem by checking for self-assignment as a separate case.
delete [] a;
a = new char[capacity];
for (int i = 0; i < length; i++)
a[i] = rtSide.a[i];
That's why. Think of it like this:
You delete whatever a points to, then allocate a new chunk of memory. The new chunk of memory contains garbage which becomes your new data. Do not be confused by the loop that does a[i] = rtSide.a[i]; that only copies the garbage onto itself.
Remember, this and rtSide both lead you to the same object. When you modify the object using this the object that rtSide refers to is modified.