代码之家  ›  专栏  ›  技术社区  ›  TSG

从函数线程安全返回QString?

  •  3
  • TSG  · 技术社区  · 10 年前

    我是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的正确方法是什么?(结果变量必须是静态的吗?结果必须是测试类的成员变量吗?)

    QString包含常量是否重要?(What-id-case 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=“one”;')

    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 回复  |  直到 10 年前
        1
  •  5
  •   phyatt    10 年前

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

    QString类提供Unicode字符串。

    QString存储一个16位QChars字符串,其中每个QChars对应 一个Unicode 4.0字符。(以上代码值的Unicode字符 65535使用代理对(即两个连续的QChars)存储。)

    Unicode是一种国际标准,支持大多数书写 目前正在使用的系统。它是US-ASCII(ANSI X3.4-1986)的超集 并且所有US-ASCII/Latin-1字符都是 在相同的代码位置可用。

    在幕后,QString使用隐式共享(写入时复制) 减少内存使用并避免不必要的数据复制。这 也有助于减少存储16位字符的固有开销 而不是8位字符。

    除了QString,Qt还提供QByteArray类来存储 原始字节和传统的8位“\0”终止字符串。大多数情况下 目的,QString是要使用的类。它贯穿始终 Qt API和Unicode支持确保您的应用程序 如果您想扩展应用程序的 市场在某个时刻。QByteArray是 当您需要存储原始二进制数据时,以及当 内存保护至关重要(如在嵌入式系统中)。

    基本上QString非常棒,几乎不用担心。你可以在任何地方使用它,无论你喜欢什么。如果您由于太频繁地附加字符串而遇到任何类型的问题,有一种特殊的方法可以使用字符串生成器,但根据我的经验,在尝试使QString更好之前,还有很多其他地方需要改进。

    直接回答您的问题:

    这安全吗?c编译器是否确保返回值在内存中停留足够长的时间,以便调用函数使用?(或者这会导致内存损坏)。如果是后者,返回QString的正确方法是什么?(结果变量必须是静态的吗?结果必须是测试类的成员变量吗?)

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

    QString包含常量是否重要?(What-id-case 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 += "!";
    }
    

    希望这会有所帮助。

        2
  •  1
  •   Kuba hasn't forgotten Monica    10 年前

    QString 是一个值类,如果不能从函数中返回它,它将是无用的。这里和 std::string 两者都可以按照你的演示方式使用。

    您所指的“常量字符串”的概念是虚构的。没有这样的事。声明 result = "foo"; 不会产生某种特殊的字符串。这不是C,你不会返回 const char * -这是有充分理由的。

    线程安全方面与字符串无关。您显示的方法体可以是静态方法,因为它不使用实例的任何数据。它也是一个纯函数,根本无法访问任何共享状态。这样的纯函数根据定义是线程安全的,因为它们不访问共享状态。您可能希望用一个更接近您的问题并实际演示一些线程问题的示例来修改您的问题。

    Q字符串 与其他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");