将一个字符串赋值给一个字符串 return 类型的函数而不用复制

Assign a string to a string return type function without copying

我想学习如何高效写作(谁不会),我希望我的示例涉及熟悉且简单的概念。我实际上正在使用 Qt,但我希望这不是问题,因为这个问题很笼统。我有一个功能是这样的:

QString elide(const QString& text, int length)
{
    if (text.length() < length) 
        return text;
    
    QString elided = text.mid(0, length);
    elided.append("...");

    qDebug() << &elided[0];

    return elided;
}

然后我用这个函数赋值一个字符串,它是一个成员变量:

void AllergiesTile::refresh()
{
    if (patient->allergies.isEmpty())
        allergies = noInfo;
    else
    {
        allergies = elide(patient->allergies, 50);
        qDebug() << &allergies[0];
    }
}

noInfo是一个QString成员变量,赋值为“No information”,但这并不重要。问题是,当我在 elide 函数中调试字符串的第一个字符的地址时,以及过敏分配后的地址(在省略的情况下) - 它们是不同的。所以这里有一个复制过程。如何避免?即使我在 elide 函数中使用 allergies = std::move(patient->allergies, 50) 或 return std::move(elided) 之类的东西,复制仍然存在。

编辑:显然我想了解移动语义,但即使在这个简单的例子中,我也很难实现它们。我知道如果省略复制,可能的性能提升可以忽略不计,但这里的问题是原则问题,以及事情如何运作。

C++ 不保证 elide() 使用 return 的方式的复制省略。这可以更详细地讨论,但很明显,这将是无关紧要的。还有另一个更根本的问题在起作用。最重要的是,您无法保证 return 从 elide() 中删除隐式副本,此处。

最近的 C++ 标准确实允许编译器 可选地 在这里省略一个副本,但即使那样也不能真正帮助你,因为调用函数中发生了什么:

allergies = elide(patient->allergies, 50);

这是将 elide() 中的 return 值分配给 不同的对象 。简而言之,这就是某种形式的复制,不可避免。它可能不会成为实际副本(这会调用对象的赋值运算符)。但是这里发生了某种复制,以某种方式。就像太阳从东方升起一样,每天(两极附近除外)。

另一方面,如果 returned 值用于构造 一个新对象,例如:

auto allergies = elide(patient->allergies, 50);

现在有可能(但不保证)如果编译器在 return 从函数中获取值时省略隐式复制,则不会发生复制,并且在 elide() 内部对象在 allergies “是”的地方“就地”得到有效构建。

但是您 returned 值分配给现有 对象。这使世界变得不同。 elide() 中构造的对象必须 是一个不同的对象,原因很明显。因此,出于根本原因,无法删除此副本。