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: お願いします

作成済み (char *): 1: 私

作成済み (char *): 2: 削除

空の作成: 3

空ロード: 3: 削除してください

空の作成: 4

空ロード: 4: 私を削除してください

私を削除してください

削除 4: 私を削除してください

削除 2: 削除

削除 1: 私

削除 0: お願いします

これらは削除されません

削除してください

問題は、一時的なオブジェクトが式で作成された理由です + 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 に答える