2013-10-19 20 views
0

我正在玩C++来提醒自己。所以我尝试了运算符+重载返回引用。此动机是为了避免不必要的对象复制。看看这个例子。我使用+创建了类String和串联的字符串。这只是实验,所以你会注意到一些丑陋的东西作为公共属性。从临时对象重载operatora和表达式返回引用

这里是代码的相关部分。

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执行此我得到以下输出

创建(字符*):0:请

创建(字符*):1:我

创建(字符*):2:删除

创建空:3

空装:3:请删除

创建空:4

空装:4:请删除我

请删除我

删除4:请删除我

删除2:删除

删除1:我

删除0:请

这些不会被删除

请删除

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

+0

阅读[此](http://en.wikipedia.org/wiki/Copy_elision)和[此] (http://stackoverflow.com/questions/3106110/what-is-move-semantics),然后停止写难看的代码。你没有保存任何东西。 –

+0

它故意丑陋,因为我想快速看到实际上用临时对象做了什么。这当然不是生产或任何严重的事情。 – ognjenmi

+0

但无论如何感谢文章。 – ognjenmi

回答

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

您手动创建了该对象,然后返回对其的引用。因此,编译器没有插入delete运算符。所以,你不能返回引用没有内存泄漏和手动destroing对象。

例如在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);