I am playing around with C++ to remind myself about it. So I experimented with operator + overloading returning reference. Motive for this is to avoid unnecessary copying of objects. Look at the example. I created class String and concatenated strings with +. It was just experimental so you'll notice some ugly stuff as public attributes.
Here are relevant parts of the code.
String.hpp
#ifndef STRING_HPP_
#define STRING_HPP_
#include <iostream>
using namespace std;
#ifndef CPP11
typedef wchar_t unicode16;
#else
typedef char16_t unicode16;
#endif //CPP11
class String {
unicode16 * value;
unsigned strLength;
void initEmpty() {
value = 0L;
strLength = 0;
}
static unsigned counter;
public:
static String ** trash;
unsigned id;
String::String() : value(0L), strLength(0){
id=counter++;
trash[id]=this;
cout << "Creating empty: " << id << "\n";
}
String::String(const String &str);
String(const char *);
String(const unicode16 *);
unsigned length() const {
return strLength;
}
~String() {
wcout << L"Deleting " << id << ": " << value << L"\n";
trash[id]=0L;
delete value;
}
String & operator +(String &);
unicode16 * getValue() {
return value;
}
};
#endif /* STRING_HPP_ */
String.cpp
#include "String.hpp"
#include "../exception/IllegalArgumentException.h"
#include <string.h>
unsigned String::counter = 0;
String ** String::trash = new String *[100]();
String::String(const String & str) {
value = new unicode16[str.strLength + 1];
strLength = str.strLength;
for(int i = 0; i < strLength ; i++) {
value[i] = str.value[i];
}
value[strLength] = 0;
id = counter++;trash[id]=this;
wcout << L"Created (copy): " << id << ": " << value << L"\n";
}
String::String(const char *charArray) {
if (charArray == 0L) {
throw IllegalArgumentException("Char array pointer is null");
}
strLength = strlen(charArray);
value = new unicode16[strLength + 1];
for (int i = 0; i < strLength; i++) {
value[i] = (unicode16)charArray[i];
}
value[strLength] = 0;
id = counter++;trash[id]=this;
wcout << L"Created (char *): " << id << ": " << value << L"\n";
}
String::String(const unicode16 *utfArray) {
if (utfArray == 0L) {
throw IllegalArgumentException("Unicode array pointer is null");
}
strLength = wcslen(utfArray);
value = new unicode16[strLength + 1];
for (int i = 0; i < strLength; i++) {
value[i] = utfArray[i];
}
value[strLength] = 0;
id = counter++;
trash[id]=this;
wcout << L"Created (unicode): " << id << ": " << value << L"\n";
}
String & String::operator +(String &str) {
unsigned newLength = length() + str.length();
unicode16 * newArray = new unicode16[newLength + 1];
wcscpy(newArray, value);
wcscpy(newArray + strLength, str.value);
String * strPointer = new String();
strPointer->value = newArray;
strPointer->strLength = newLength;
String &result = *strPointer;
wcout << L"Empty loaded: " << result.id << ": " << result.value << L"\n";
return result;
}
And the main method
#include "../string/string.hpp"
#include <iostream>
using namespace std;
int metodica(void) {
String & please = String("Please");
String meString = "me";
String & me = meString;
String & delStrRef = String(" delete ");
String & result1 = please + delStrRef + me;
wcout << result1.getValue() << L"\n";
delete &result1;
return 0;
}
int main(void) {
metodica();
cout << "These are not deleted\n";
for (int i = 0; i < 100; i++) {
if (String::trash[i] != 0L) {
wcout << String::trash[i]->getValue() << "\n";
}
}
}
Executing this in CDT using VS2010 compiler and linker i got following output
Created (char *): 0: Please
Created (char *): 1: me
Created (char *): 2: delete
Creating empty: 3
Empty loaded: 3: Please delete
Creating empty: 4
Empty loaded: 4: Please delete me
Please delete me
Deleting 4: Please delete me
Deleting 2: delete
Deleting 1: me
Deleting 0: Please
These are not deleted
Please delete
The question is why temporary object created in the expression please + delStrRef + me; is not deleted. Shouldn't it get deleted at the end of the expression or it goes differently if reference is temporary object and not the object itself.
String & String::operator +(String &str) {
...
String * strPointer = new String();
...
String &result = *strPointer;
...
return result;
}
You manually created the object, and then returned the reference to it. Hence, the compiler did not insert delete
operator. So, you cannot return reference without memory leak and manually destroing the object.
For example in Qt
library operator+
implemented as
Q_EXPORT inline const QString operator+( const QString &s1, const QString &s2 ) {
QString tmp( s1 );
tmp += s2;
return tmp;
}
Where operator+=
declared as QString &operator+=( const QString &str );