My string class destructor implementation - c++

Having such simple program:
#include <iostream>
#include <string>
#include <windows.h>
using namespace std;
extern char MsgBuff[300];
class MyStr {
string* strPtr;
public:
// "normal" constructor
MyStr(const string& strPtr) : strPtr(new string(strPtr)) {}
// destructor
~MyStr() {
if(strPtr != NULL)
delete strPtr;
}
// copy constructor
MyStr(const MyStr& x) : strPtr(x.strPtr) {
OutputDebugStringA("copy constructor");
}
// move constructor
MyStr(MyStr&& x) : strPtr(x.strPtr) {
x.strPtr = nullptr;
OutputDebugStringA("copy constructor");
}
};
int main() {
MyStr foo("Exam");
MyStr foo2 = foo;
return 0;
}
The program throws an exception: Exception thrown: read access violation. As i invesigated it's caused by the destructor code - destroying these two objects (foo, foo2) we are freeing TWICE the same memory pointed by strPtr pointer.
How can this code be fixed to preserve the logic and avoid the exception?

A few things wrong with this code...
MyStr(const MyStr& x) : strPtr(x.strPtr) {
OutputDebugStringA("copy constructor");
}
This code makes "shallow" copy of the class as it only assigns adresses to existing object instead of creating a new one. This is the main problem, because as main() goes out of scope destructors will be called on all initialized objects. First ~foo will be called. "Succesfully". Then ~foo2 will be called and as it is still a valid object destructor will be called.
if (strPtr != NULL)
will pass, because nowhere in your code do you set strPtr to "nullptr" and so delete on uninitialized object will be called. This will cause the memory access violation.
Few things to keep in mind:
Please use std::string as much as possible. (people that implement this know what they're doing)
Never ever use raw pointers unless absolutely necessary. (this is just realy ugly way of doing things with really no benefits. Use std::shared_ptr and std::unique_ptr instead.)
Always set pointer to NULL after calling delete on it. (This goes without saying. Dont leave objects set to invalid adresses.)
NEVER.. use extern and/or global variables NEVERR!! (This just shows bad code design/structure)
Also this is not "bad" in "main" cpp file, but try to avoid using "using namespace std;". This will save you some headache when working with multiple namespaces.
Now for the "fixed" code part.. I assume you want to do a wrapper for string, so here you go:
#include <iostream>
#include <memory>
#include <string>
#include <windows.h>
class MyStr {
std::shared_ptr<std::string> m_ptrStr;
public:
// "normal" constructor
MyStr(const std::string& strPtr) : m_ptrStr(std::make_shared<std::string>(strPtr)) {}
// destructor
~MyStr() { }
// shallow copy constructor (you can do this since you have "smart" pointer)
MyStr(const MyStr& x) : m_ptrStr(x.m_ptrStr) {
OutputDebugStringA("copy constructor");
}
// move constructor
MyStr(MyStr&& x) noexcept : m_ptrStr(std::move(x.m_ptrStr)) {
OutputDebugStringA("move");
}
};
int main() {
MyStr foo("Exam");
MyStr foo2 = foo;
return 0;
}

The problem in the code is with the copy ctor.
// copy constructor
MyStr(const MyStr& x) : strPtr(x.strPtr) {
OutputDebugStringA("copy constructor");
}
Here you don't create a shallow copy of the string.
The solution is doing one of the following:
If memory and creation time is not an issue, create a deep copy by creating a new string and putting it inside of MyStr.
Using std::shared_ptr<std::String> instead of raw std::string*, which is a bit wasteful in my opinion.
Using copy-on-write approach. On copy, you don't create a new string, but rather another reference to the same resource, and as far as I know, this used to be the approach used by std::string. (you can read more about it on)
Another issue is using std::string since it is already doing exactly what you are trying to accomplish. If you want to make your own implementation, using raw pointers, use char * and not std::string *.

Presumably you're doing this to experiment with raw pointers as opposed to needing to house a string.
When using naked pointers, you need to properly implement copy constructors and assignment operators such that you perform a "deep copy" of the addressed data.
Whenever I do this, I write a "clone" method that would in your case perform:
void clone (MyStr const& src)
{
strPtr = new string(*src.strPtr);
}
Also I would recommend using the "free-and-nil" idiom to avoid double-deletion:
if (srcPtr)
{
delete srcPtr;
srcPtr = nullptr;
}
I recommend the Book "Professional C++" by Marc Gregoire which covers this kind of detail. I own copies of the 3rd and 4th editions. https://www.amazon.co.uk/Professional-C-Marc-Gregoire/dp/1119421306

Related

If you std::move an object can you delete the original safely? Should you?

I have difficulty understanding std::move behavior and would like to know whether it is necessary to manually call delete for newStudentDan after "addStudent" in an example like below, or it will be a memory leak.
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
class Student {
public:
Student(std::string name): name_{name} {}
void addParent(std::string name) {
parent_ = name;
}
private:
std::string name_;
std::string parent_;
};
class School {
public:
//constructor
School(): name_{"default"} {}
Student* addStudent(Student student);
Student* addStudent(std::unique_ptr<Student>&& ptr, int);
private:
std::string name_;
std::vector<std::unique_ptr<Student>> students_;
};
Student* School::addStudent(Student student) {
return this->addStudent(std::unique_ptr<Student>{ new Student{std::move(student)}}, 1);
}
Student* School::addStudent(std::unique_ptr<Student>&& ptr, int) {
Student* retval{ptr.get()};
students_.push_back(std::move(ptr));
return retval;
}
int main() {
School newSchool;
Student* newStudentDan = new Student("Dan");
newStudentDan->addParent("Lisa");
newSchool.addStudent(*newStudentDan);
//...continues
return 0;
}
I think your confusion stems from two related, but separate concepts: storage duration and object lifetime. Moving an object, just like copying, causes a new object to be created, without ending the lifetime of the original. On the other hand, a memory leak is a failure to deallocate memory that is no longer needed, which is indeed the case with newStudentDan in your example.
The direct answer to your question is that yes, you should always delete any object allocated with new, regardless of what you do with it.
Move semantics can be demonstrated without the use of dynamic allocations:
Student& School::addStudent(Student student) {
students_.push_back(std::move(student));
return students_.back();
}
int main() {
School newSchool;
Student newStudentDan {"Dan"};
newStudentDan.addParent("Lisa");
newSchool.addStudent(std::move(newStudentDan));
}
Perhaps the easiest way to think about it is this: std::move does not actually move anything, it allows the compiler to select functions that may "steal" the object's resources, such as by invoking its move constructor or move-assignment operator. These may not be available, in which case the copy operations are used if available.
In the snippet above, Student has an (implicit) move constructor, so it will be the one used to create the new object from newStudentDan. The lifetime of newStudentDan continues until the end of main() and it will still have some memory associated with it, even though its actual data are now owned by the vector. But because it's now a stack variable (it has "automatic storage duration"), destruction and deallocation occur automatically.
Note that not even move constructors do any moving either, in the sense of relocating data in memory. For example, as this detailed answer explains, the move constructor for std::unique_ptr simply copies a pointer and sets the source pointer to nullptr, without touching the object itself. For better or worse, the word "move" is just a term that indicates the type of semantics where the source object will not necessarily be equivalent to the target object.

C++ RAII - Do I have this right?

I'm new to C++ and am new to using RAII for deleting allocated memory. I wrote this code as a sample of what it would take to automatically allocate and later delete a character array. I know there's a string class out there, but thought I'd start with the older stuff first. Does this sample look correct? And is it the way others would create a string and delete it automatically?
#include <iostream>
using namespace std;
class StringGetter
{
private:
char* theString;
public:
StringGetter(char* name)
{
this->theString = new char[1024];
strcpy_s(this->theString, strlen(name) + 1, name);
}
char* GetString()
{
return this->theString;
}
~StringGetter()
{
delete[] this->theString;
}
};
int main()
{
char* response;
{
StringGetter getter("testing");
response = getter.GetString();
}
cin.get(); // pauses the console window
}
It looks like you get the main idea, but there's a couple things worth mentioning.
1) As #chris mentioned, you're forgetting your copy constructor, copy assignment operator, move constructor, and move assignment operator. Copy should be either manually written or disabled, move can be defaulted. (aka You've not followed the rule of 5)
2) Prefer to use std::unique_ptr to represent ownership. It's already done all of the hard work for you. By keeping your wrapped string in a std::unique_ptr the default versions of the copy/move special functions will preserve correctness (though you'll still want to implement the copy operations if you want them to be enabled).
Here's what this might look like:
class StringGetter {
public:
explicit StringGetter(char* name) {
strSize = strlen(name);
str = std::unique_ptr<char[]>(new char(strSize+1));
std::copy_n(name, strSize + 1, str.get());
}
StringGetter(const StringGetter& other) {
strSize = other.strSize;
str = std::unique_ptr<char[]>(new char(strSize+1));
std::copy_n(other.str.get(), strSize + 1, str.get());
}
StringGetter(StringGetter&& other) = default;
StringGetter& operator=(const StringGetter& rhs) {
auto temp = rhs;
swap(temp);
return *this;
}
StringGetter& operator=(StringGetter&& rhs) = default;
const char* getString() const noexcept {
return str.get();
}
void swap(StringGetter& other) {
std::swap(str, other.str);
std::swap(strSize, other.strSize);
}
private:
std::unique_ptr<char[]> str;
int strSize;
};
Miscellaneous items:
1) Note that std::unique_ptr handles the RAII. When I replace 'str' in the copy constructor, it deletes the old string automatically.
2) I size the dynamically allocated memory to match the input string. This prevents overflows/wasted memory.
3) The constructor is explicit. This prevents undesirable conversions. Rule of thumb is to use the explicit keyword on all single argument constructors.
4) I made getString constant so that you can still call it on const instances of the class.
5) I replaced the str-family copy function with std::copy_n. It's more general and can avoid certain pitfalls in obscure cases.
6) I used the copy-swap idiom in the copy assignment operator. This promotes code reuse/avoids duplication.
7) When C++14 comes out, replace the std::unique_ptr constructor call with std::make_unique for added exception-safety and to remove redundancy.
Here is an attempt at an RAII class that does something similar:
template<std::size_t N>
class StringGetter_N
{
private:
std::unique_ptr<char[]> buffer;
public:
StringGetter_N()
{
buffer.reset( new char[N] );
buffer.get()[0] = 0;
}
explicit StringGetter_N(char const* name)
{
buffer.reset( new char[N] );
strcpy_s(buffer.get(), N-1, name);
buffer.get()[N-1] = 0; // always null terminate
}
StringGetter_N( StringGetter_N&& other ) = default;
char* GetString()
{
return buffer.get();
}
};
class StringGetter : StringGetter_N<1024> {
explicit StringGetter( const char* name ):StringGetter_N<1024>(name) {}
StringGetter():StringGetter_N<1024>() {}
};
notice that I delegated the resource management to a smart pointer. Single responsibility principle means that the resource management object (like a smart pointer) can do just that, and if you want to write a class that represents a heap-allocated buffer of fixed size, you delegate that sub problem to the smart pointer, and just manage it in your class.
As it happens, std::unique_ptr properly implements
But really, it is usually much simpler to just use a std::vector, as you can usually determine how much space you need at run-time before needing a buffer to write to.
If you do implement your own RAII class, you should follow these rules:
Single argument constructors that are not copy/move constructors should usually be explicit.
If you implement a non-trivial destructor, you must (implement or block usage of) (copy and/or move constructor) and (copy and/or move operator=). This is known as the rule of 3 (or rule of 5 in C++11).
Your RAII class should do little except manage the resource. If you want to do something else, use an RAII class to manage the resource, then store it within another class that does the fancy extra work.

About destructors in c++

The question is how to correctly delete name in A destructor?
class A{
private:
char *name;
public:
A(char *n) : name(n) {}
~A(){
//???
}
}
int main(){
A *a = new A("name");
delete a;
return 0;
}
Given that you do not change the constructor, then the correct way is to not delete anything. Ownership of the string belongs to the client, since you are not creating a copy.
However, the right way of rewriting this is to let the constructor allocate a copy of the string with new[] and let the destructor deallocate it with delete[].
And the really right way is to let std::string do the whole thing for you, and not write an explicit destructor at all:
#include <string>
class A{
private:
std::string name;
public:
A(std::string n) : name(std::move(n)) {}
};
This, by the way, allows you not to worry about the Rule of Three, which means you won't have to bother writing a copy constructor, a move constructor, a copy assignment operator, a move assignment operator, a destructor and whatnot.
You are not allowed to delete a pointer to string constant "name".
As your class does not own any objects or memory blocks, it should not delete anything.
In this example you don't need to delete name. "name" is just a pointer to some some place in executable image, not memory allocated with new/malloc/something_else.
"name" occupies static memory that the compiler automatically sets aside. If you delete that memory, the behavior is undefined (i.e. crash). You only 'delete' memory that you 'new' in the first place.
The simplest thing is to use proper C++ (std::string) and avoid naked pointers, as that simplifies management of resources.
The problem with your interface is that the type A claims ownership of the argument, but you cannot claim ownership of a string literal, as those are managed by the implementation. You could go on trying to decide whether the caller should create deep copy and pass it to a A or if A design should be changed not to attempt to claim ownership and make a copy out of that. But the fact is that things are much simpler if you just use higher level constructs:
class A {
std::string name;
public:
A(const std::string& name) : name(name) {}
};
No need to manually copy data around, no need for a destructor or a copy constructor... all works out of the box.

Malloc on a struct containing a std::vector

Here is the situation :
I use a malloc to allocate memory for a struct.
The struct contains various items such as pointers, string variables and vectors.
The fact is, when we use malloc, no constructors are called. Using a code similar to the following one, I've experienced some situation where some variables worked while others didn't.
Note : The following code doesn't compile. It's purpose is only to illustrate the situation.
struct MyStruct
{
MyClass* mFirstClass;
bool mBool;
std::string mString;
std::vector<MyClass> mVector;
};
int main()
{
MyStruct* wMyStructure;
wMyStructure = (MyStruct*) malloc (sizeof(MyStruct));
MyClass wMyClassObject;
wMyStructure->mFirstClass = new MyClass();
wMyStructure->mFirstClass->func();
wMyStructure->mBool = false;
wMyStructure->mString = "aString";
wMyStructure->mVector.push_back(wMyClassObject);
return 0;
}
By using pointers instead of those variables (std::string* mString), followed by a call to the object constructor (mString = new std::string;) Exception are not thrown.
However, I've experienced a situation where the mString was used without problem without the constructor being called, but when it came to the vector, the application exit automatically.
This left me with many questions:
When will an object throw an exception if no constructor were used?
In the situation I experienced, only the vector caused problem. Could mString be left as it is or should I call it's constructor?
What would be the safest way, using malloc, to do the whole thing?
Using object without constructing it must be an undefined behaviour. Anything may happen at any moment. If you do this, you must not rely on any part of your code to run smoothly, because the language doesn't guarantee anything in this case.
Your code causes undefined behaviour, because your wMyStructure does not point to an object, so you may not use the accessor operator -> on it.
An object only commences its life after its constructor has completed. Since you don't call any constructor, you do not have an object.
(If your struct were a POD, i.e. just consisting of primitive types and PODs, then this would be OK, because PODs have trivial constructors, which do nothing.)
The concrete problem you're facing is that the string and vector members of your struct didn't get to call their constructors, so those members don't exists, and hence the entire object doesn't.
If you want to decouple memory management from object construction, you can use placement syntax:
// get some memory
char arena[HUGE_VAL];
void * morespace = malloc(HUGE_VAL);
// construct some objects
MyClass * px = new (arena + 2000) MyClass; // default constructor
YourClass * py = new (morespace + 5000) YourClass(1, -.5, 'x'); // non-default constructor
(You have to destroy those objects manually, px->~MyClass(); etc., when you're done with them.)
It is undefined behaviour to use a non-initialized object. Exception may be thrown at any time- or not at all.
1 ) When will an object throw an exception if no constructor were used ?
If you don't call the constructor, there is no object. You have just allocated some space.
2 ) In the situation I experienced, only the vector caused problem. Could mString be left as it is or should I call it's constructor ?
This is all undefined behavior, just about anything could happen. There are no rules.
3 ) What would be the safest way, using malloc, to do the whole thing ?
The safest way would be not to use malloc, but allocate using new that will call constructors. It is as simple as this
MyStruct* wMyStructure = new MyStruct;
None of the other answers appear to explain what the compiler is doing. I'll try to explain.
When you call malloc the program reserve some memory space for the struct. That space is filled with memory garbage, (i.e. random numbers in place of the struct fields).
Now consider this code:
// (tested on g++ 5.1.0 on linux)
#include <iostream>
#include <stdlib.h>
struct S {
int a;
};
int main() {
S* s = (S*)malloc(sizeof(S));
s->a = 10;
*((int*)s) = 20;
std::cout << s->a << std::endl; // 20
}
So when accessing a member of a struct you are actually accessing a memory position, there should be no unexpected behavior when writing to it.
But in C++ you can overload operators. Now imagine what would happen if the overloaded assignment operator need the class to be initialized, like in the code below:
// (tested on g++ 5.1.0 on linux)
#include <iostream>
#include <stdlib.h>
class C {
public:
int answer;
int n;
C(int n) { this->n = n; this->answer = 42; }
C& operator=(const C& rhs) {
if(answer != 42) throw "ERROR";
this->n = rhs.n; return *this;
}
};
struct S {
int a;
C c;
};
int main() {
S* s = (S*)malloc(sizeof(S));
C c(10);
C c2(20);
c = c2; // OK
std::cout << c.n << std::endl; // 20
s->c = c; // Not OK
// Throw "ERROR"
std::cout << s->c.n << std::endl; // 20
}
When s->c = c is executed the assignment operator verifies if s->c.answer is 42, if its not it will throw an error.
So you can only do as you did in your example if you know that the overloaded assignment operator of the class std::vector does not expect an initialized vector. I have never read the source code of this class, but I bet it expects.
So its not advisable to do this, but its not impossible to be done with safety if you really need. You just need to be sure you know the behavior of all assignment operators you are using.
In your example, if you really need an std::vector on the struct you can use a vector pointer:
class MyClass { ... };
struct S {
std::vector<MyClass>* vec;
}
int main() {
S s;
MyClass c;
s.vec = new std::vector<MyClass>();
s.vec->push_back(c);
}

Visual Studio 2010 C++ runtime error

I came across strange behavior in Visual Studio 2010 C++ compiler.
Following code compiles but throws "Debug assertion failed" after execution with
message:
"_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)"
Compiles and runs smoothly under GCC. Is it my fault?
#include <iostream>
#include <vector>
using namespace std;
typedef unsigned int uint;
class Foo {
vector<int*> coll;
public:
void add(int* item) {
coll.push_back(item);
}
~Foo() {
for (uint i = 0; i < coll.size(); ++i) {
delete coll[i];
coll[i] = NULL;
}
}
};
int main()
{
Foo foo;
foo.add(new int(4));
Foo bar = foo;
return 0;
}
You didn't implement a copy constructor and copy assignment operator (see rule of three). This results in a shallow copy of the pointers in your vector, causing a double delete and the assertion. EDIT: Double delete is undefined behavior so both VS and gcc are correct here, they're allowed to do whatever they want.
Typically when you implement a destructor with non-trivial behavior you'll also need to write or disable copy construction and copy assignment.
However in your case do you really need to store the items by pointer? If not, just store them by value and that would fix the problem. Otherwise if you do need pointers use shared_ptr (from your compiler or boost) instead of raw pointers to save you from needing to write your own destructor/copy methods.
EDIT: A further note about your interface: Interfaces like this that transfer ownership of passed in pointers can cause confusion by people using your class. If someone passed in the address of an int not allocated on the heap then your destructor will still fail. Better is to either accept by value if possible, or clone the passed in item making your own call to new in the add function.
You're deleting item twice, because the line
Foo bar = foo;
Invokes the default copy constructor, which duplicates the itempointer, rather than allocating and copying the data.
The problem is both the bar and foo member's vector element is same. When foo goes out of scope it's destructor is called which deallocates the pointer leaving the bar vector element dangling.bar destructor tries to deallocate it's vector element which was left dangling and is causing you the runtime error. You should write a copy constructor.
Foo bar = foo; // Invokes default copy constructor.
Edit 1: Look at this thread to know about Rule of three
The simpler solution here is not to use int* in the first place.
#include <iostream>
#include <vector>
using namespace std;
typedef unsigned int uint;
class Foo {
vector<int> coll; // remove *
public:
void add(int item) { // remove *
coll.push_back(item);
}
// remove ~Foo
};
int main()
{
Foo foo;
foo.add(4); // remove `new` call
Foo bar = foo;
return 0;
}
In general, try to avoid new.
If you cannot, use a smart manager (like std::unique_ptr) to handle the memory clean-up for you.
In any case, if you're calling delete manually, you're doing it wrong. Note: not calling delete and letting the memory leak is wrong too