Domanda

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.

È stato utile?

Soluzione

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 );

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top