C++ Object Copy - c++

I'm just looking at the following code snippet:
#include<iostream>
#include<cstring>
using namespace std;
class String
{
private:
char *s;
int size;
public:
String(const char *str = NULL); // constructor
~String() { delete [] s; }// destructor
void print() { cout << s << endl; }
void change(const char *); // Function to change
};
String::String(const char *str)
{
size = strlen(str);
s = new char[size+1];
strcpy(s, str);
}
void String::change(const char *str)
{
delete [] s;
size = strlen(str);
s = s + 1;
s = new char[size+1];
strcpy(s, str);
}
int main()
{
String str1("StackOverFlow");
String str2 = str1;
str1.print();
str2.print();
str2.change("StackOverFlowChanged");
str1.print();
str2.print();
return 0;
}
I expect the output as:
StackOverflow,
StackOverflow,
StackOverflow,
StackOverflowChanged.
Before str2.change("StackOverFlowChanged") line, both str1 and str2's s point to the same memory location. However, in change method, since the pointer value changed, I except now str1 and str2's s point to the different locations and this is not the case. Can somebody explain why this is the case?

After calling str2.change, str1 no longer has a valid pointer. Since the two objects were sharing the same pointer, by deleting the array in one object, the other object now points to a deleted array. Attempting to access the array pointed to by str1 is undefined behavior, so str1.print() is invalid code.
Now, in this particular case, odds are good that the new char[] in str2.change just so happens to return a pointer to an address identical to the one that was just deleted. After all, the memory was just freed up, and no other allocations were made in the meantime. So while str1's pointer is still invalid, it just so happens to work out to pointing at a valid string by the time str1.print gets called.
But that's just happenstance; an implementation didn't have to do that. Undefined behavior is undefined, and you need to properly follow the Rule of 5. Or just use std::string.

The problem is that you called delete[] on the memory pointed by str1.
The runtime library is then allowed to reuse the same memory for the next allocation call and apparently this is what happened.
str1 didn't change the memory it pointed to, but the content changed.
Note that using a pointer to memory after it has been delete[]d is undefined behavior. So indeed anything can happen.
When you write classes that own heap allocated memory a lot of care should be taken about who owns the memory and when this memory is going to be released; in particular a lot of attention should go to copy constructor and assignment operator because the automatically generated code is rarely the correct one in case of memory owned using raw pointers.

No, str1 and str2 do not point to the same memory location, before str2.change("StackOverFlowChanged") line. str2 is in a different location but with the same value as of str1. You can verify this using -
cout << &str1 << '\t' << &str2 << endl;
It will show that they have different locations in memory.

Related

How could I use a reference of a pointer when re-allocating memory?

Unlike in the C, as what i've learned about C++, there is no instruction realloc in C++ for it is not recommended. But when I was creating a function that concatenates strings and at the same time can be dynamically re-allocating the given strings' memory without using vector, I've come to need some code just like as the realloc instruction functioning.
So what i've come up with is that using a reference of a pointer(in the code char* &des) could adjust the size of memory by using the usual instruction of C++, new and delete. However, an error occured: "[Error] invalid initialization of non-const reference of type 'char*&' from an rvalue of type 'char*'" Why is it impossible to initialize char*& type with the type char*? Isn't it the same as a statement char* &des = str0? The total code is as follows:
void Mystrcat(char* &des, const char* src) {
int des_len = Mystrlen(des); // Mystrlen just returns the length of a string with the type unsigned int excluding null character
int src_len = Mystrlen(src);
char* temp_str = des;
des = new char[des_len + src_len + 1];
//a copy process
for(int i = 0; i < des_len; i++) {
des[i] = *(temp_str + i);
}
for(int i = des_len + 1; i < des_len + src_len + 1; i++)
des[i - 1] = *(src + i - des_len - 1);
}
int main() {
char str0[100] = "Hello";
Mystrcat(str0, ", World!");
std::cout << str0 << std::endl; //expecting "Hello, World!" to be printed
return 0;
}
What i've tried before is just writing the parameter char* des instead of char* &des. But unlike in main function, it was not possible to get the size of total str0 array in Mystrcat function by simply using sizeof. As a result, I thought it would be good to use pointer reference. I was expecting this a reference of a pointer parameter to be working properly because it is equal to the statement char* &des = str0.
The problem here is:
char str0[100] = "Hello";
str in this case has a pinned (static) memory address. It's immutable in terms of its address -- so to speak -- because it's not a pointer to a string, but an array of characters of a size that can be evaluated at compile-time (not dynamically allocated). Making str itself point to a different address makes no sense and invites a whole lot of chaos. Even modifying the original pointer address to a dynamically-allocated array is chaos since you need the original address to properly free it. Think of an array of T as T* const (the address is immutable even if the contents are mutable and even if dynamically allocated, you need to keep the original address unmodified).
But in general as a non-profit advertisement of sorts, I want to encourage embracing value semantics as much as you can over pointer/reference ones. So instead of:
void Mystrcat(char* &des, const char* src)
{
// Modify the address of 'des' in place.
}
You can do:
[[nodiscard]] char* Mystrcat(char* des, const char* src)
{
// Input an address to a string and return an address to a new string.
}
Then you can pass an address to your array, get a pointer to a new modified copy (same thing you were doing before), and store the pointer to the new array (along with freeing it when you're done). There's little benefit to modifying things in place if you're just going to allocate a new string anyway.
This is still ignoring the conventional advice that you should use std::string which is what I think you need now and wholeheartedly echo over all this low-level pointer stuff and manual heap allocation and deallocation (which can be disastrous without the use of RAII when combined with thrown exceptions) But later you might want to deviate from it if the SBO is too large or too small or if the SBO optimization is counter-productive, for example but that's diving deep into things like custom memory allocators and whatnot and something you typically reserve until you encounter profiler hotspots and really know what you're doing.

C++ implicit class to char* conversion

I'm doing an exercise right now, so I will say right away that I don't want to use std::string to solve my problem.
I have a simple class that has a few fields and among them is char* text field that can be assigned and re-written or re-allocated.
class MyClass
{
private:
char* name;
...
public:
operator char*() const { return name;}
}
What I'm trying to do is make an implicit conversion to char* so that I can do this in my program:
Myclass s = "Hello" //allocates 6 bytes and pust a 0-terminated "Hello/0" line into "name"
char* c = s
s = "Hello World" //re-allocates memory, frees previous memory
cout << "Str: " << s << " Char: " << c;
Obviously, just as I noticed even before testing, when the re-allocation of "name" happens and the memory is freed - "c" now points to garbage.
So this code is no-go and I fully understand why.
I could allocate new memory and return a pointer to it, I guess:
operator char*() const
{
int length = strlen(name)+1;
char* ptr = new char[length]
std::copy(name, name+length, ptr);
return ptr;
}
but in this case, if I later re-assign "c" to something else - then the memory will never be freed, right? If I do this:
c = "Bye";
then basically the memory that I copied "name" to will still remain allocated and leaK?
The question is: how to make this right? Should I even worry about this, or do I simply assume that the user who re-assigns "c" should take care of clearing the memory first?
I will repeat that my goal is to do this through memory manipulation and pointers rather than safely use std::string.
Thank you!

how come data is still present in the pointer, even after freeing before returning value

Dint find the exact link to my answer, so asking this simple question in terms where the function returns the char *
I wrote the code in this way so that the concat function itself should allocate & free the memory.
Can anyone plz help with the questions:
1) Is the freeing of memory placed correctly? (I ran Valgrind & found no issues as well)
2) How come pointer "ptr" which is allocated holding value, as per my understanding, if a memory to a ptr is freed, then value also should be lost right? Kindly correct me if am wrong.
char * concat(char *str1, char *str2)
{
char *ptr;
ptr=(char*)malloc(strlen(str1)+strlen(str2)+1); //allocated+1 for NULL character as well
int i=0,j=0;
while(str1[i]!='\0')
{
ptr[j]=str1[i];
printf("letter from src is %c\n",str1[i]);
i++; j++;
}
i=0;
while(str2[i]!='\0')
{
ptr[j]=str2[i];
j++;i++;
}
ptr[j]='\0';
cout<<ptr;
free(ptr);
return ptr;
}
int main()
{
char *str1="hello";
char *str2="world";
cout<<str1<<endl;
cout<<str2<<endl;
char *res=concat(str1,str2);
return 0;
}
Valgrind isn't complaining because you don't access res in main. If you do read res then I expect that you will get Valgrind errors, and quite likely crashes in a bigger application.
You need to change the end of concat to remove the call to free, i.e.,
cout<<ptr;
return ptr;
}
Also rather than hand written loops, you could use strcat, i.e.,
ptr=(char*)malloc(strlen(str1)+strlen(str2)+1);
strcat(ptr, str1);
strcat(ptr, str2);
Then in main you can use your result. For instance
int main()
{
char *str1="hello";
char *str2="world";
cout<<str1<<endl;
cout<<str2<<endl;
char *res=concat(str1,str2);
cout << "res from main: " << res << "\n";
free(res);
return 0;
}
When you call ptr = malloc(/*size*/) a block of free memory of at least the size you requested is allocated to you by the system; and the memory address of the start of this block is returned to you.
When you call free(ptr), you're telling the system you no longer want that block of memory. However your pointer will still point to the same memory address after the call.
The implementation of free is system dependant. Accessing memory at this address after you've called free(ptr) is undefined behaviour.

How to make char array and std::string "in a relationship"?

I'm looking for a way to associate a char array with a string so that whenever the char array changes, the string also changes. I tried to put both char array and string variables in a union but that didn't worked as the compiler complained...
Any ideas are welcome...
class Observable_CharArray
{
char* arr;
std::function<void(char*)> change_callback;
public:
Observable_CharArray(int size, std::function<void(char*)> callback)
: arr(new char[size]), change_callback(callback){}
~Observable_CharArray()/*as mentioned by Hulk*/
{
delete[] arr;
}
void SetCallback(std::function<void(char*)> callback)
{
change_callback = callback;
}
/*other member function to give access to array*/
void change_function()
{
//change the array here
change_callback(arr);
}
};
class Observer_String
{
std::string rep;
void callback(char* cc)
{
rep = std::string(cc);
}
public:
Observer_String(Observable_CharArray* och)
{
och->SetCallback(std::bind(&callback, this, _1));
}
/*other member functions to access rep*/
};
The design can definitely be improved.
There can be other ways to solve your actual problem rather than observing char arrays.
The problem is that the std::string may change the string array inside (especially when it resizes). For instance, c_str returns the address of the current string - documentation says that "The pointer returned may be invalidated by further calls to other member functions that modify the object.".
If you're sure you won't call string methods (hence the string will stay at the same memory location), you could try accessing the c_str pointer (your char array) directly and modify its content.
std::string str = "test";
char* arr = (char*)str.c_str();
arr[3] = 'a';
NOTE: I strongly advice against this unless in a testing context.
In other words, the string class doesn't guarantee it's going to stay in the same place in memory - meaning trying to access it through a char array is impossible.
The best is to create another string class that enforces the char array to always stay the same size (and so can stay in the same memory position all the time). You could also create a bigger array (max size string for instance) to cope with any string size changes - but that should be enforced in your wrapper class.
Well you can do this, but you shouldn't
#include <iostream>
#include <string>
int main()
{
std::string test("123456789");
std::cout << test << "\n";
char* data = &test.front(); // use &(*test.begin()) for pre-C++11 code
for ( size_t i(0); i < test.size(); ++i )
{
data[i] = 57 - i;
}
std::cout << test << "\n";
}
Output will be
123456789
987654321
This however goes again everything std::string is trying to facilitate for you. If you use data, you risk causing UB and changes to test may make data point to garbage.
You should not do this!
However, there are many (dangerous) ways to achieve it:
char* cStr = const_cast<char*>(cppStr.c_str());
or
char* cStr = const_cast<char*>(cppStr.data());
or
char* cStr = &cppStr[0];
But beware that the cppStr might be reallocated whenever you touch it, hence invalidating your cStr. That would crash at some point in time, although maybe not immediately (which is even worse).
Therefore, if you are going to do this anyway. Make sure to cppStr.reserve(SOMETHING) *before* you get the cStr out of it. This way, you will at least stabilise the pointer for a while.

Where to free up memory of a dynamic array created inside a function

This is in reference to the discussion in this topic here
How to have a char pointer as an out parameter for C++ function
In the code below, where do I free the memory of pTemp? Is it not required?
Would things would have changed in anyway if instead of array of chars there was array of integers?
void SetName( char **pszStr )
{
char* pTemp = new char[10];
strcpy(pTemp,"Mark");
*pszStr = pTemp;
}
int main(int argc, char* argv[])
{
char* pszName = NULL;
SetName( &pszName );
cout<<"Name - "<< pszName << endl;
delete [] pszName;
cin.get();
return 0;
}
You're assigning pTemp to *pszStr, and pszStr points to pszName.
Therefore, delete [] pzxName deletes the allocated memory as required.
The confusion is a good example of why you should avoid weird C-style idioms and manual memory management. It would be much clearer as:
#include <string>
#include <iostream>
std::string GetName() {return "Mark";}
int main() {
std::string name = GetName();
std::cout << "Name - " << name << std::endl;
}
with no pointers, new or delete required.
You don't need to.
The memory allocated to it is deallocated when you call:
delete [] pszName;
Note, that new/new [] returns you a address and to avoid a memory leak you need to call delete/delete [] on the exact same address and only once.
What you have in above code is two different pointers(pszName and pTemp) pointing to the same address which was returned by new []. So calling delete [] on one suffices.
In C++ you are much better off using a std::string instead of char * and in case of other data types, You surely can use smart pointers and save yourself the explicit memory management.
pTemp, the variable itself, is deallocated once the function exits since it was allocated on the stack in the first place. The array whose pointer was put into pTemp persists outside the function via the argument passed to it, pszName. When the value in this variable is deleted, the heap memory used by the array will be freed.