繁体   English   中英

标准库是如何实现 std::swap 的?

[英]How does the standard library implement std::swap?

STL中swap函数是如何实现的? 是不是就这么简单:

template<typename T> void swap(T& t1, T& t2) {
    T tmp(t1);
    t1=t2;
    t2=tmp;
}

在其他帖子中,他们讨论了为您自己的班级专门化此功能。 为什么我需要这样做? 为什么我不能使用std::swap函数?

std::swap是如何实现的?

是的,问题中提出的实现是经典的 C++03 实现。

std::swap的更现代 (C++11) 实现如下所示:

template<typename T> void swap(T& t1, T& t2) {
    T temp = std::move(t1); // or T temp(std::move(t1));
    t1 = std::move(t2);
    t2 = std::move(temp);
}

这是在资源管理方面对经典 C++03 实现的改进,因为它可以防止不需要的副本等。它,C++11 std::swap ,要求类型TMoveConstructibleMoveAssignable ,从而允许实施和改进。

为什么我需要提供自定义实现?

当您的实现比标准版本更高效或更具体时,通常会建议对特定类型的swap自定义实现。

一个经典的(C++11 之前的)示例是当您的类管理大量资源时,复制和删除这些资源的成本很高。 相反,您的自定义实现可以简单地交换实现交换所需的句柄或指针。

随着std::move和可移动类型(并以此实现您的类型)的出现,大约在 C++11 及以后,这里的许多原始基本原理开始消失; 但是,如果自定义交换比标准交换更好,请实施它。

如果通用代码适当地使用ADL机制,它通常能够使用您的自定义swap

STL中swap函数是如何实现的?

哪个实现? 这是一个规范,而不是一个具体的库。 如果你的意思是我的编译器的标准库如何做到的,要么告诉我们是哪个编译器,要么自己阅读代码。

是不是就这么简单:

这本质上是 C++11 之前的原始版本。

这种非专业化的实现强制复制:对于您的示例中的T = std::vector<SomethingExpensive> ,代码转换为:

template<typename T> void swap(T& t1, T& t2) {
  T tmp(t1); // duplicate t1, making an expensive copy of each element
  t1=t2;     // discard the original contents of t1,
             // and replace them with an expensive duplicate of t2
  t2=tmp;    // discard the original contents of t2,
             // and replace them with an expensive duplicate of tmp
}            // implicitly destroy the expensive temporary copy of t1

所以为了交换两个向量,我们基本上创建了三个 有三个动态分配和许多昂贵的对象复制,并且这些操作中的任何一个都可能抛出,可能使参数处于不确定状态。

由于这显然很糟糕,因此为昂贵的容器提供了重载,并且鼓励您为自己的昂贵类型编写重载:例如。 std::vector可以访问向量的内部结构,并且可以交换两个向量而无需进行所有复制:

template <typename T> void swap(vector<T> &v1, vector<T> &v2) { v1.swap(v2); }
template <typename T> void vector<T>::swap(vector<T>& other) {
  swap(this->size_, other.size_); // cheap integer swap of allocated count
  swap(this->used_, other.used_); // cheap integer swap of used count
  swap(this->data__, other.data_); // cheap pointer swap of data ptr
}

请注意,这根本不涉及任何昂贵的副本,没有动态(取消)分配,并且保证不会抛出。

现在,这种特殊化的原因是 vector::swap 可以访问 vector 的内部结构,并且可以安全有效地移动它们而无需复制。

为什么我需要做这件事[专门...为你自己的班级]?

Pre-C++11,出于与std::vector相同的原因 - 使交换高效且异常安全。

从 C++11 开始,你真的不需要——如果你提供移动构造和赋值,或者编译器可以为你生成合理的默认值。

新的通用交换:

template <typename T> void swap(T& t1, T& t2) {
    T temp = std::move(t1);
    t1 = std::move(t2);
    t2 = std::move(temp);
}

可以使用移动构造/分配来获得与上面的自定义向量实现基本相同的行为,而根本不需要编写自定义实现。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM