2014-08-28 58 views
3

我是Qt的新手 - 但這可能是一個非常基本的C++問題。我有一個簡單的函數返回一個QString:從函數返回一個QString - 線程安全嗎?

QString testclass::myfunc(int i) 
{ 
    QString result; 
    switch (i) { 
    case 1: result = "one"; break; 
    case 2: result = "two"; break; 
    } 
    return result; 
} 

這是否安全? c編譯器是否確保返回值在內存中保留足夠長的時間以供調用函數使用? (或者這是否會損害內存損壞)。如果是後者,返回QString的正確方法是什麼? (結果var必須是靜態的嗎?結果是否必須是testclass的成員變量?)

QString是否包含常量? (什麼id情況3分配結果到一個隨機字符串)

如果myfunc是一個靜態方法,我想從不同的線程調用?我是否必須通過引用傳遞額外的Qstring以確保每個調用者都獲得自己的變量(並返回void)?


下面是實際的功能(清理了一下) - 並注意這個功能是靜態的情況下,使一個區別:

QString L::toString(const L::editions &level) 
{ 
    QString levelStr; 
    switch (level) { 
     case L::one: 
      levelStr = "one"; 
      break; 
     case L::two: 
      levelStr = "two"; 
      break; 
     case L::three: 
      levelStr = "thre"; 
      break; 
     default: 
      levelStr = "Internal Error"; 
      break; 
    } 
    return levelStr; 
} 

,但Valgrind的抱怨(線121「levelStr = 「一」;')

34 bytes in 1 blocks are definitely lost in loss record 197 of 716 
    in L::toString(L::edition const&) in /mnt/lserver2/data/development/haast/src/linfo.cpp:121 
    1: malloc in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so 
    2: QArrayData::allocate(unsigned long, unsigned long, unsigned long, QFlags<QArrayData::AllocationOption>) in /opt/Qt/5.3/gcc_64/lib/libQt5Core.so.5.3.1 
    3: QString::QString(int, Qt::Initialization) in /opt/Qt/5.3/gcc_64/lib/libQt5Core.so.5.3.1 
    4: /opt/Qt/5.3/gcc_64/lib/libQt5Core.so.5.3.1 
    5: QString::fromUtf8_helper(char const*, int) in /opt/Qt/5.3/gcc_64/lib/libQt5Core.so.5.3.1 
    6: QString::fromUtf8(char const*, int) in <a href="file:///opt/Qt/5.3/gcc_64/include/QtCore/qstring.h:492" >/opt/Qt/5.3/gcc_64/include/QtCore/qstring.h:492</a> 
    7: QString::operator=(char const*) in <a href="file:///opt/Qt/5.3/gcc_64/include/QtCore/qstring.h:609" >/opt/Qt/5.3/gcc_64/include/QtCore/qstring.h:609</a> 
    8: L::toString(L::Lconst&amp;) in <a 
+0

該函數返回對象(對象上不指針),所以它是安全的(因爲有的QString的拷貝構造,這將複製局部變量的內容'result'到呼叫者的外部變量) – Ilya 2014-08-28 05:33:12

+0

我是這麼認爲的....但看看Valgrind的輸出I以上 – TSG 2014-08-28 05:40:32

+0

加我最近升級到最新的QT(5.3.1),突然我的Qt中Valgrind是顯示我,離開我抓我的頭泄漏的地段。如果知道Qt/valgrind問題,請告訴我。 – TSG 2014-08-28 05:55:03

回答

5

http://qt-project.org/doc/qt-5/qstring.html#details

QString類提供了一個Unicode字符串。

QString存儲一個16位QChars字符串,其中每個QChar對應一個Unicode 4.0字符的 。 (Unicode字符與代碼值以上 65535使用替代對,即兩個連續的QChars存儲。)

Unicode是一種國際標準今天支持大多數書寫 系統在使用中。它是US-ASCII(ANSI X3.4-1986) 和Latin-1(ISO 8859-1)的超集,所有US-ASCII/Latin-1字符均爲 ,可用於相同的代碼位置。

在幕後,QString使用隱式共享(寫時複製)到 可減少內存使用量並避免不必要的數據複製。這個 也有助於減少存儲16位字符 而不是8位字符的固有開銷。

除了QString,Qt還提供了QByteArray類來存儲 原始字節和傳統的8位'\ 0'終止的字符串。對於大多數 目的,QString是您想要使用的類。它貫穿於Qt API的整個 中,並且Unicode支持可確保您的應用程序 易於翻譯,如果您想在某個時間擴展您的應用程序的市場。 QByteArray爲 適合的兩種主要情況是,當您需要存儲原始二進制數據時,以及何時存儲器保存非常重要(如嵌入式系統中)。

基本上QString是真棒,幾乎無憂無慮。你可以在任何地方使用它,無論你喜歡什麼。如果您經常遇到任何拖慢添加字符串的速度的問題,則有一種使用字符串生成器的特殊方法,但根據我的經驗,在嘗試使QString更好之前,還有很多其他地方需要改進。

並直接回答您的問題:

這是安全嗎? c編譯器是否確保返回值在內存中保留足夠長的時間以供調用函數使用? (或者這是否會損害內存損壞)。如果是後者,返回QString的正確方法是什麼? (是否結果VAR必須是靜態的?結果是否必須TestClass中的一員變種?)

在上述所有上述情況下,它是安全的。只要任何函數具有QString的句柄,共享指針等就會將其保存在內存中。一旦完全超出範圍,它將自行清理。

QString是否包含常量? (什麼id情況3分配結果到一個隨機字符串)

不,沒關係。

如果myfunc是一個靜態方法,我想從不同的線程調用?我是否必須通過引用傳遞額外的Qstring以確保每個調用者都獲得自己的變量(並返回void)?

你應該用交叉線程保護包裝它,例如QMutexLocker

UPDATE:QMutexLocker例如

// In your constructor 

m_mutex = new QMutex(); 


// When accessing a shared element across threads 

{ 
    QMutexLocker locker(m_mutex); 
    // Accessing a variable is now threadsafe! 
    m_sharedDataString += "!"; 
} 

希望有所幫助。

1

QString是值類,它會是無用的,如果你不能從一個函數返回。這與std::string沒有什麼不同。兩者都可以用你演示的方式使用。

你引用的「const字符串」的概念是虛構的。沒有這樣的事情。聲明result = "foo";不會生成某種特殊字符串。這不是C,你沒有返回const char * - 這是一個很好的理由。

線程安全方面與字符串沒有太大關係。您顯示的方法體可能是一個靜態方法,因爲它不使用任何實例的數據。它也是一個純粹的功能,根本無法訪問任何共享狀態。這樣的純函數根據定義是線程安全的,因爲它們不訪問共享狀態。你可能希望用一個更接近你的問題的例子來修改你的問題,並且實際上演示了一些線程問題。

QString,像其他Qt的隱含共享值類,是線程安全的,只要特定實例的它從只有一個線程訪問。不要緊,該實例可能是從分配或從另一個字符串實例複製。例如:

QString a = "foo"; 
{ 
    QFutureSynchronizer sync; 
    sync.addFuture(QtConcurrent::run([&a] { a.append("bar"); })); 
    sync.addFuture(QtConcurrent::run([&a] { a.append("baz"); })); 
} 
// This is not thread safe: a might be concurrently accessed from two 
// threads. The behavior is undefined. It might format your hard drive. 

QString c = "Homer"; 
QString d = c; 
{ 
    QFutureSynchronizer sync; 
    sync.addFuture(QtConcurrent::run([&c] { c.append("'s"); })); 
    sync.addFuture(QtConcurrent::run([&d] { d.append(" and Elmer's"; })); 
} 
// This is thread safe. One of the threads will safely deep-copy the 
// c's contents. 
Q_ASSERT(c == "Homer's"); 
Q_ASSERT(d == "Homer and Elmer's"); 
+0

很好的使用lambda函數。我仍然在研究即將學習'QtConcurrent'。我對'QThread'非常滿意,我還沒有離開它。感謝您的見解。 – phyatt 2014-08-28 16:01:29