从重载的运算符和带有临时对象的表达式返回引用

时间:2013-10-19 23:20:11

标签: c++ overloading operator-keyword temporary

我正在玩C ++以提醒自己。所以我尝试了operator +重载返回引用。这样做的动机是避免不必要的对象复制。看看这个例子。我用+创建了类String和连接字符串。它只是实验性的,所以你会注意到一些丑陋的东西作为公共属性。

以下是代码的相关部分。

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

主要方法

#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";
        }
    }
}

使用VS2010编译器和链接器在CDT中执行此操作我得到了以下输出

创建(char *):0:请

创建(char *):1:我

创建(char *):2:删除

创建空:3

空载:3:请删除

创建空:4

空载:4:请删除我

请删除我

删除4:请删除我

删除2:删除

删除1:我

删除0:请

这些不会被删除

请删除

问题是为什么在表达式中创建临时对象请+ delStrRef + me;未删除。它不应该在表达式的末尾被删除,或者如果引用是临时对象而不是对象本身则会有所不同。

1 个答案:

答案 0 :(得分:0)

String & String::operator +(String &str) {
    ...
    String * strPointer = new String();
    ...
    String &result = *strPointer;
    ...
    return result;
}

您手动创建了对象,然后返回对它的引用。因此,编译器没有插入delete运算符。因此,您无法在没有内存泄漏的情况下返回引用并手动销毁对象。

例如在Qtoperator+中实现为

Q_EXPORT inline const QString operator+( const QString &s1, const QString &s2 ) {
    QString tmp( s1 );
    tmp += s2;
    return tmp; 
}

operator+=声明为QString &operator+=( const QString &str );

的地方
相关问题