5

以下部分演示了我的问题:(GCC 上的编译错误)

stringstream ss;
string s;
ss << "Hello";

// This fails:
// s.swap(ss.str());

// This works:
ss.str().swap(s);

我的错误:

constSwap.cc:14: error: no matching function for call to 'std::basic_string<char, std::char_traits<char>, std::allocator<char> >::swap(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)'
basic_string.tcc:496: note: candidates are: void std::basic_string<_CharT, _Traits, _Alloc>::swap(std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>]

虽然我知道 stringstream 中的 str() 返回一个临时值,但它没有意义,也不是很明显我应该使用局部变量作为参数而不是我的第一直觉来调用临时值上的交换。

显然,直接赋值效果更好,并且较新的 C++ 标准具有完美的移动语义,但这些不适用于我的实现。

Visual Studio 没有给出这个问题,因为它对 C++ 标准放宽了。我已经理解了对临时事物的整个 const 引用(我认为这是我的编译错误的原因)。

我的问题:任何人都可以向我解释这是否是唯一的解决方案,也许可以向我解释将来如何考虑这个问题,以便我可以发现并解决类似的问题?

(如果没有人有任何深刻的见解,我至少在这里为有类似问题的人发布这个)

4

3 回答 3

7

您不能将临时对象绑定到非常量引用。由于这个原因,ss.str()不能将临时返回的 from 传递给std::string::swap希望修改其参数的对象(因此它使用 接受其参数non-const&)。

第二个版本在您调用允许的临时对象上的成员函数时工作。

但是为什么你首先要交换呢?通常,一个简单的:

std::string s(ss.str());

应该足够好。这并不比交换效率低(至少在具有移动语义的 C++0x 中),但同时更具可读性。

于 2010-07-12T22:44:12.993 回答
2

在使用 swap-with-temporary 成语足够多次之后,像这样的行

std::vector<int>().swap(v); // clear and minimize capacity

或者

std::vector<int>(v).swap(v); // shrink to fit

这似乎并没有那么格格不入。将 swap 作为临时对象的成员函数调用是正常的。当然,如前所述,使用 swap 填充默认构造的字符串而不是使用复制构造函数并不是那么惯用的。

于 2010-07-12T22:53:02.940 回答
1

您不能将临时作为参数传递给的原因swap是该参数是通过非常量引用传递的。临时对象只能由 const 引用绑定。这分布在第 8.5.3 节中,适当的是第 5 段,第二个项目符号:

§8.5.3 对“cv1 T1”类型的引用由“cv2 T2”类型的表达式初始化,如下所示:

  • [要点一,不适用于此处:绑定到非常量 ref ]

  • 否则,引用应为非易失性 const 类型(即 cv1 应为 const)。

以相反方向编写调用的原因是该标准允许在临时对象上调用变异成员函数。

§3.10/10 对象的左值是修改对象所必需的,但在某些情况下,类类型的右值也可用于修改其所指对象。[示例:为对象(9.3)调用的成员函数可以修改该对象。]

您对未来的要求的推理是,虽然您可以通过它自己的函数修改临时变量,但您不能将它传递给可以修改它的函数或方法(通过非常量引用传递)

于 2010-07-12T23:24:50.323 回答