0

我正在玩 C++ 来提醒自己。所以我尝试了操作符+重载返回引用。这样做的动机是避免不必要的对象复制。看例子。我创建了类 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_ */

字符串.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: 请

创建(字符 *):1:我

创建 (char *): 2: 删除

创建空:3

空载:3:请删除

创建空:4

空载:4:请删除我

请删除我

删除4:请删除我

删除2:删除

删除1:我

删除0:请

这些不会被删除

请删除

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

4

1 回答 1

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

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

例如在Qt库中operator+实现为

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

于 2013-10-19T23:27:50.197 回答