std::swap() เป็นฟังก์ชันใน Header <algorithm> (C++98) และ <utility> (C++11+) ใช้สลับค่าของ Object สองตัวได้อย่างมีประสิทธิภาพ
Syntax
#include <utility> // C++11+
// หรือ #include <algorithm> // C++98
template<class T>
void swap(T& a, T& b) noexcept(/*...*/);
โค้ดตัวอย่างพื้นฐาน
#include <iostream>
#include <utility> // หรือ <algorithm>
using namespace std;
int main() {
int x = 35, y = 75;
cout << "Before swap: x = " << x << ", y = " << y << endl;
swap(x, y);
cout << "After swap: x = " << x << ", y = " << y << endl;
return 0;
}
ผลลัพธ์
Before swap: x = 35, y = 75 After swap: x = 75, y = 35
การทำงานภายใน (Implementation)
// Conceptual Implementation (C++11 Move Semantics)
template<class T>
void swap(T& a, T& b) noexcept(is_nothrow_move_constructible<T>::value &&
is_nothrow_move_assignable<T>::value) {
T tmp = std::move(a); // Move a to tmp
a = std::move(b); // Move b to a
b = std::move(tmp); // Move tmp to b
}
// Pre-C++11 (Copy-based)
template<class T>
void swap(T& a, T& b) {
T tmp = a; // Copy
a = b; // Copy
b = tmp; // Copy
}
Overload สำหรับ Arrays
#include <iostream>
#include <utility>
#include <array>
using namespace std;
int main() {
int a[3] = {1, 2, 3};
int b[3] = {4, 5, 6};
swap(a, b); // std::swap มี Overload สำหรับ Array (C++11)
cout << "a: "; for (int x : a) cout << x << " "; // 4 5 6
cout << "\nb: "; for (int x : b) cout << x << " "; // 1 2 3
// std::array
array<int, 3> arr1 = {1,2,3}, arr2 = {4,5,6};
swap(arr1, arr2);
return 0;
}
Custom Swp สำหรับ Class ของตัวเอง (ADL)
#include <iostream>
#include <utility>
#include <string>
using namespace std;
class MyString {
string data;
public:
MyString(const string& s = "") : data(s) {}
// Friend swap function (Argument-Dependent Lookup)
friend void swap(MyString& a, MyString& b) noexcept {
using std::swap;
swap(a.data, b.data); // ใช้ std::swap สำหรับ string
cout << "MyString::swap called" << endl;
}
const string& get() const { return data; }
};
int main() {
MyString s1("Hello"), s2("World");
cout << "Before: " << s1.get() << ", " << s2.get() << endl;
swap(s1, s2); // เรียก MyString::swap ผ่าน ADL
cout << "After: " << s1.get() << ", " << s2.get() << endl;
return 0;
}
ผลลัพธ์
Before: Hello, World MyString::swap called After: World, Hello
Best Practices: Swap Idiom
1. Copy-and-Swap Idiom (สำหรับ Copy Assignment)
class MyClass {
int* data;
size_t size;
public:
MyClass(size_t n = 0) : size(n), data(new int[n]) {}
~MyClass() { delete[] data; }
// Copy Constructor
MyClass(const MyClass& other) : size(other.size), data(new int[other.size]) {
copy(other.data, other.data + size, data);
}
// Copy Assignment via Copy-and-Swap
MyClass& operator=(MyClass other) { // Pass by Value (Copy)
swap(*this, other); // Swap Resources
return *this; // other (old data) ถูก Destroy
}
// Swap Function
friend void swap(MyClass& a, MyClass& b) noexcept {
using std::swap;
swap(a.data, b.data);
swap(a.size, b.size);
}
};
2. Move Semantics + Swap
class Movable {
int* data;
size_t size;
public:
Movable(size_t n = 0) : size(n), data(new int[n]) {}
~Movable() { delete[] data; }
// Move Constructor
Movable(Movable&& other) noexcept : data(other.data), size(other.size) {
other.data = nullptr;
other.size = 0;
}
// Move Assignment
Movable& operator=(Movable&& other) noexcept {
if (this != &other) {
delete[] data;
data = other.data;
size = other.size;
other.data = nullptr;
other.size = 0;
}
return *this;
}
friend void swap(Movable& a, Movable& b) noexcept {
using std::swap;
swap(a.data, b.data);
swap(a.size, b.size);
}
};
std::swap vs Custom Swap
| ด้าน | std::swap | Custom Swap |
|---|---|---|
| Generic Types | ทำงานได้ทุก Type ที่ MoveAssignable | ต้องเขียนเองต่อ Class |
| Performance | ดี (Move Semantics) | ดีที่สุด (ทราบโครงสร้างภายใน) |
| Exception Safety | Strong (noexcept ถ้า Move noexcept) | ขึ้นกับการ Implement |
| ADL | หา Custom Swp ใน Namespace เดียวกับ Type | ต้องเป็น Friend หรือ Free Function |
การใช้งานกับ STL Algorithms
#include <algorithm>
#include <vector>
int main() {
vector<int> v = {3, 1, 4, 1, 5};
// Reverse ใช้ swap ภายใน
reverse(v.begin(), v.end()); // {5, 1, 4, 1, 3}
// Sort ใช้ swap (และ move)
sort(v.begin(), v.end()); // {1, 1, 3, 4, 5}
// Partition
partition(v.begin(), v.end(), [](int x){ return x % 2 == 0; });
return 0;
}
สรุป
std::swap(a, b)สลับค่า a, b แบบ Generic- Include
<utility>(C++11+) หรือ<algorithm> - ใช้ Move Semantics (C++11) → เร็ว ไม่ Copy
- เขียน Custom Swap ให้ Class ของเอง (Friend + ADL)
- ใช้ใน Copy-and-Swap Idiom สำหรับ Exception-Safe Assignment
- STL Algorithms ใช้ swap ภายใน (sort, reverse, partition, etc.)