I have a class String with the following members:
Class String{
...
private:
char* word
int length
}
String's copy assignment returns a String& and allocates word on the heap.
I also have a linked list class written in C that has a function:
void *popFront(struct List *list)
{
struct Node prevHead = list->head
list->head = prevHead->next;
void *info = prevHead->info;
free(prevHead);
return info;
}
My task is to write the same function for a C++ linked list that uses the C function. This is what I have:
String List::popFront()
{
String s = (*(String *) ::popFront(&list));//casting the void * to String
return s;
}
The C++ method should return the object by value. That's what I thought the method would do. However,
I'm getting memory leaks. Any hint on how I need to modify List::popFront() so that it returns by value? Thanks.
First store the returned pointer locally as a pointer to string, then make a local copy of the string, then delete the object, the pointer points to and finally return the local copy.
EDIT:
Btw. you can use c++11's smart pointers to avoid the extra copy:
String List::popFront()
{
auto s = std::unique_ptr<String>((String*) ::popFront(&list));
return *s;
}
but that is probably not, what your teacher aims at.
popFront removes the element from the linked list and frees the node, but not the info portion. This is the responsibility of the caller of popFront, e.g.
String *s = (String *) ::popFront(&list);
delete s;
But you must also keep a copy, which you can return from the method
String List::popFront()
{
String *s = (String *) ::popFront(&list);
String tmp = *s;
delete s;
return tmp;
}
You declare String List::popFront() which returns an object, not a pointer. And String s = ... declares an object, not a pointer or reference. So assigning s a value constructs a new object s being a copy of what ::popFront returned, then a next copy of s is returned and s itself gets destroyed. However the object unlinked by ::popFront() remains on a heap, making a leak.
Don't create an intermediate copy of String object, return the pointer to unlinked object, so that a caller can link it to its own list or delete it after use:
String *List::popFront()
{
String *s = (String *) ::popFront(&list);//casting the void * to String *
return s;
}
Related
I recently started to learn C++, and one of the tasks of my "self-made-up program for making things in language clear to me" is develop a class which will have functionality similar to Java strings. So, it should be something like immutable strings, i.e. when you make changes on such a string, it should not change its internal chars array, but instead return a modified copy of itself. It's pretty straightforward, but I encountered some undestanding problems regarding memory management.
Things I already know about MM in C++:
objects which were created on the stack are disposed when they go out of scope
if an object is created in the heap (i.e. with new keyword), it should be disposed manually with delete (unless you use smart pointers.)
But if a class acts like immutable and, because of that fact, its objects implicitly create themselves sometimes, there are memory leak risks, as I can imagine. Here's an example (String is my educational class):
String *str1 = new String("str1"); // creating new object in the heap
String *str2 = new String("str2"); // another one
str1 = str2; // pointer to str1 object is lost, thereby it's memory leak
- or -
str1 += str2; // we haven't disposed old value of str1, now it's replaced by new object made of str1 + str2
Some implemetation code (not including headers, etc.) is below. All questions asked can be read in comments.
String.h
class String {
public:
explicit String(const char *);
String operator+(String);
String operator+(String *);
String operator=(String);
String operator=(String *);
String operator+=(String);
String operator+=(String *);
/* . . . */
private:
String() = default;
String(String *, String *);
byte *_contents;
int _length;
String.cpp
String::String(const char *original) {
int len = std::strlen(original);
this->_contents = new byte[len + 1];
std::strcpy((char *)this->_contents, original);
this->_length = len;
}
String::String(String *first, String *second) {
/* not so important implementation details */
this->_contents = new byte[capacity + 1];
/* more of not so important implementation details*/
}
String String::operator+(String another) {
return operator+(&another);
}
String String::operator+(String *another) {
return String(this, another);
}
// clang warning: "operator =() should always return String&",
// and if I correct that, then it says this operator should return only *this. Why?
String String::operator=(String replacement) {
return operator=(&replacement);
}
String String::operator=(String *replacement) {
// I guess, now I should dispose internal array, because one object is replaced by another. Right?
// Or, maybe, it should be "delete(this)"?
delete[](this->_contents);
this->_contents = replacement->_contents;
this->_length = replacement->_length;
this->_isWide = replacement->_isWide;
return *this;
}
String String::operator+=(String addition) {
return operator+=(&addition);
}
String String::operator+=(String *addition) {
auto concatenated = new String(this, addition);
// Same question here as above.
delete[](this->_contents);
return operator=(concatenated);
}
I have a struct like these:
struct Node {
void *data;
Node *l, *r;
}
And I should use function:
void push(Queue *q, void *data, int priority) {
Node *n = new Node;
n->data = data;
// place node in queue
}
I'm trying to read strings in loop, but after that I got queue where all values in nodes are similar.
void read_input(Queue *q) {
string s;
int p;
cin >> s >> p;
// problem is here
push(q, (void *) s.c_str(), p);
}
void main() {
Queue *q = create();
for (int i = 0; i < 5; i++) {
read_input(q);
}
}
How can I fix that? Why string s always has the same address?
Like Trantor said, you using s.c_str() which is a private pointer of string s; and is valid only inside read_input function.
Every call to read_input will use this pointer that is destroyed every time you reach read_input end (out of scope).
You see the same pointer, probably because its on the stack. Its a coincidence.
To fix your issue, you need to create a copy of the characters and store them in node->data. However you will also need to think where to delete it. E.g. OnNodeDestroy event or similar.
The problem is, you are saving (temporary) pointers to the private internals of temporary objects of class std::string in your queue push call. They become invalid after leaving read_input, and may be even reused internally, so the pointer seems not to change.
Instead you should work with copies, allocate your own memory for the strings.
When you have created a string object compiler will allocate the memory from stack and all the time that string object will pointing to that particular memory location (static memory allocation in this case) only. In your structure void *data pointer will also always pointing to that same memory location. Hence the last value entered into string object will reflect in all the node in your stack. To fix this you have to dynamically allocate memory each time so that the data pointer should pointing to different memory location and you will get different value.
void read_input(Queue *q) {
//string s;
char *s = (char *)malloc(50);
int p;
cin >> s >> p;
push(q, (void *) s, p);
}
I'm trying out a C# style string implementation in C++.
I have created an object and a pointer for class String, and assigned the object to the pointer. When i try to modify the object via the pointer instead of modifying the existing object i want to create a new object and make the pointer point it.
So i have overloaded the "=" operator, and creating a new object in the operator overloaded method. In order to reflect the change i need to use ss=*ss = "name";
Any suggestion to improve this code.
Below is my sample code
class String
{
char *str;
public:
String(char* str_in)
{
str = new char[strlen(str_in)];
strcpy(str, str_in);
}
String* operator=(char* s)
{
return new String(s);
}
};
int main()
{
String s="sample";
String *ss;
ss = &s;
ss=*ss = "name";
return 0;
}
I also tried to modify the this pointer, but not working as expected
String *ptr;
ptr = const_cast<String*>(this);
ptr = new String(s);
I would recommend some changes like this:
#include <string.h>
class String
{
char *str;
public:
String(const char* str_in)
{
str = new char[strlen(str_in)];
strcpy(str, str_in);
}
~String()
{
delete [] str;
}
String& operator=(const char* s)
{
char* tmp = new char[strlen(s)];
strcpy(tmp, s);
delete [] str;
str = tmp;
return *this;
}
};
int main()
{
String s("sample");
String *ss;
ss = &s;
ss = new String("name");
delete ss;
return 0;
}
First of all, you need an appropriate destructor or you are going to have a memory leak when String gets destroyed. Deleting the char* fixes this (since it is an array, we use the array delete).
Secondly, in C++, we almost always return a reference for operator= (not a pointer). So this revised operator= function is probably better - it deletes the old string, allocates memory for the new string, copies the new string, and returns *this.
Third, you can use const char* instead of char* for the constructor and assignment operator since you are not editing it.
In main(), I also created a new object for the pointer to point to since you requested that in the original post (and then it is deleted afterwards to avoid a memory leak).
Let me know if you have any questions with those changes.
I have made two object of string class each having char* pointer . By shallow copying, i have copied the first object into second object by shallow copying . Now both of them pointing at the same location.
What i have to do is append the char pointer through one object so that it does not make another but increase the size of original char pointer so second object point to the same location.
void String::append(char c) {
auto_ptr<StringBuffer> newdata(new StringBuffer);
newdata.get()->reserve(this->_str->length() + 1);
newdata.get()->smartCopy(this->_str);
this->_str = newdata.release();
this->_str->append(c);
}
The wrapper class of StringBuffer
void StringBuffer::reserve(int n) {
if (_length < n) {
int newlength = n; //max(_length*2,n);
char* newbuf = new char[newlength];
//copy contents of the stored string in the new buffer
revSmartCopy(newbuf);
//return stuff from the new buffer to the stored buffer
delete[] this->_strbuf;
this->_strbuf = newbuf;
this->_length = newlength;
newbuf = 0;
}
}
void StringBuffer::revSmartCopy(char* newString) {
int it = 0;
while (it < this->_length) {
newString[it] = this->_strbuf[it];
it++;
}
}
void StringBuffer::smartCopy(StringBuffer* newString) {
int shorterLength = 0;
(this->_length < newString->_length) ? shorterLength = this->_length : shorterLength = newString->_length;
int it = 0;
while (it < shorterLength) {
*_strbuf++ = *(newString->_strbuf)++;
it++;
}
}
This code is making another copying with object from whom we append pointing to new copy and older one pointing to previous
Let's assume you're doing this as an exercise, because it makes no sense otherwise.
You can't reallocate a pointer to a different size and have it at the same pointer value; this might happen accidentally, but it's impossible to enforce. Since the two objects are independent, the only way to make this work is double indirection - the pointer in your object points to a second pointer, which is the pointer to the character buffer.
You're also going to have a problem with destruction, because you have multiple objects with the same pointer. The standard library has std::shared_ptr to solve this very problem. If a pointer is shared between different objects, use shared_ptr to hold it.
Since there will only be one pointer to the actual character buffer, you can use std::unique_ptr for that one. You could use std::auto_ptr instead, and it will work fine as long as you don't try to copy it, but unique_ptr is a far better choice.
Will the following code work? -
void doSomething(char* in)
{
strcpy(in,"mytext");
}
Here's how the function is being called:
doSomething(testIn);
OtherFn(testIn);
The char* in is used in other places in the code... and we are passing it by value to the function doSomething. I understand when we pass by value, a copy of the string stored in char* is copied within the function. So, when we do a strcpy, will it copy to the local copy or to the char* in that was passed in as an argument?
My understanding is we need to do: doSomething(char* &in). Is that right?
When you want to modify just the contents of what the pointer points to, use:
doSomething(char* in)
So, yes,
void doSomething(char* in)
{
strcpy(in,"mytext");
}
will work just fine as long as in points to enough memory to hold "mytest" and a terminating null character.
There are times when you want to modify where the pointer points to, for example, by allocating new memory. Then, you need to pass a reference to a pointer.
void doSomething(char*& in)
{
in = new char[200];
strcpy(in,"mytext");
}
and use it as:
char* s = NULL;
doSomething(s);
// Now s points to memory that was allocated in doSomething.
// Use s
// make sure to deallocate the memory.
delete [] s;