从函数返回一个QString - 线程安全吗?

时间:2014-08-28 05:27:44

标签: c++ qt function return-value qstring

我是Qt的新手 - 但这可能是一个非常基本的c ++问题。我有一个返回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 if case 3将结果分配给随机字符串)

如果myfunc是一个静态方法,我想从不同的线程调用怎么办?我是否必须通过引用传入额外的Qstring以确保每个调用者获得自己的变量(并返回void)?


这是实际的功能(清理了一下) - 注意这个功能是STATIC,以防有所不同:

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

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 

2 个答案:

答案 0 :(得分: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使用隐式共享(copy-on-write)   减少内存使用并避免不必要的数据复制。这个   还有助于减少存储16位字符的固有开销   而不是8位字符。

     

除了QString之外,Qt还提供了要存储的QByteArray类   原始字节和传统的8位'\ 0'终止字符串。对于大多数   目的,QString是您要使用的类。它在整个过程中使用   Qt API和Unicode支持确保您的应用程序   如果你想扩展你的应用程序,将很容易翻译   市场在某些方面。 QByteArray的两个主要案例   适当的是当你需要存储原始二进制数据时,以及何时   记忆保存至关重要(如嵌入式系统)。

基本上QString很棒,几乎无后顾之忧。您可以随时随地使用它,无论您喜欢什么。如果你经常在追加字符串方面遇到任何变慢,那么有一种特殊的方法可以使用字符串构建器,但根据我的经验,在尝试使QString更好之前还有很多其他的地方需要改进。

直接回答你的问题:

这样安全吗? c编译器是否确保返回值在内存中保留足够长的时间以供调用函数使用? (或者这会冒内存损坏的风险)。如果是后者,返回QString的正确方法是什么? (结果var必须是静态的吗?结果必须是testclass的成员吗?)

在上述所有情况中,都是安全的。只要任何函数具有QString的句柄,共享指针等就会将其保留在内存中。一旦它完全超出范围,它就会自我清理。

QString包含常量是否重要? (id if case 3将结果分配给随机字符串)

不,没关系。

如果myfunc是一个静态方法,我想从不同的线程调用怎么办?我是否必须通过引用传入额外的Qstring以确保每个调用者获得自己的变量(并返回void)?

您应该使用跨线程保护来包装它,例如QMutexLocker

更新: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 :(得分: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");