为什么我的swap<string,string>比std版本慢得多?

6

这是我的C++代码:

inline static void swap(std::string& a1, std::string& a2) {    
    std::string temp( std::move(a1));
    a1 = std::move( a2 );
    a2 = std::move( temp );
}

我运行了这个函数1000000次,平均需要78毫秒,但是标准库的那个只需要13毫秒。我刚刚查看了std::swap的实现,发现和我的一模一样,所以为什么我的代码这么慢?

1
标准为许多标准类型专门定制了“swap”。通常这样做是为了能够处理内部工作。 - NathanOliver
3
以下是链接中的内容翻译:函数定义 void swap( basic_string& other ) noexcept;交换字符串和另一个字符串的内容。参数 other - 另一个字符串,与当前字符串交换其内容异常 noexcept - 该函数不会引发异常。复杂性 常数 - 交换两个指针,两个大小值和两个相对大小值。备注 可以通过 std::swap 来进行替换。示例 下面的代码演示了如何使用 swap() 交换两个字符串的内容:#include <iostream> #include <string>int main() { std::string str1 = "First string"; std::string str2 = "Second string";std::cout << "Before swap: str1 = " << str1 << ", str2 = " << str2 << '\n'; str1.swap(str2); std::cout << "After swap: str1 = " << str1 << ", str2 = " << str2 << '\n';}输出:Before swap: str1 = First string, str2 = Second string After swap: str1 = Second string, str2 = First string - M.M
我运行了这个函数1000000次,平均需要78毫秒。-- 你是在运行“调试”未经优化的版本吗? - PaulMcKenzie
2
也许在你的特定 std::basic_string 实现中,std::basic_string 的 std::swap 特化被声明为 friend。这将通过简单地交换内部指针和大小/容量计数器来消除所有移动赋值/移动构造函数调用。这也可以通过优化 std::swap 调用为 std::basic_string::swap 来实现。 - 3442
4
std::basic_stringstd::swap 特化可能只是执行 a1.swap(a2); - Richard Critten
有些推测,但是由于短字符串优化,该类可能不是POD。因此,上面的代码可能会扩展为考虑4种情况;a1和a2都可以是短字符串或长字符串。然而,std::string::swap很可能能够忽略区别,并交换原始字节,而不管它们的含义。当然,这只有在std库实现可以对编译器进行假设时才可能发生。 - MSalters
1个回答

7

根据标准 §21.3.2.8/p1 swap [string.special]我强调的):

template<class charT, class traits, class Allocator>
void swap(basic_string<charT, traits, Allocator>& lhs,
basic_string<charT, traits, Allocator>& rhs)
noexcept(noexcept(lhs.swap(rhs)));

1 Effects: Equivalent to: lhs.swap(rhs);

因此,std::swapstd::string 专门化/重载,并等效于调用成员函数 std::basic_string::swap
可能的实现如下:
template<class Elem, class Traits, class Alloc> 
inline
void
swap(std::basic_string<Elem, Traits, Alloc>& left, 
     std::basic_string<Elem, Traits, Alloc>& right) noexcept(noexcept(left.swap(right))) {
  left.swap(right);
}

为什么您的实现速度较慢,我猜测即使您将一个字符串移动到另一个字符串中,临时字符串的析构函数仍然会被调用。这在上述与STL兼容的实现中并非如此。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接