Setelah header <numeric> tuntas, kita membuka kotak peralatan kecil yang paling sering dipakai lintas program C++: fungsi utilitas dari <utility> dan <algorithm>. Ukurannya pendek — sering hanya satu baris — tetapi justru karena itu mereka ada di hampir setiap file kode: std::swap untuk menukar dua nilai, std::exchange untuk mengganti nilai sambil mengambil yang lama, std::min/std::max/std::clamp untuk membatasi angka, dan std::make_pair untuk membentuk std::pair tanpa menulis tipe. Chapter ini juga memberi pratinjau std::move, yang penjelasan penuhnya menanti di Section Move Semantics dan Value Categories. Kita bahas semuanya lewat satu program utama, lalu pendalaman per fungsi.

swap, exchange, min, max, clamp dalam Satu Program #

cpp
#include <algorithm>  // std::min, std::max, std::clamp
#include <iostream>   // std::cout
#include <string>     // std::string
#include <utility>    // std::swap, std::exchange, std::pair, std::make_pair

int main() {
    // std::swap: menukar isi dua objek dengan tipe yang sama
    int x = 3, y = 8;
    std::swap(x, y);
    std::cout << "swap int      : x=" << x << " y=" << y << "\n";

    std::string s1 = "asal", s2 = "tujuan";
    std::swap(s1, s2);
    std::cout << "swap string   : s1=" << s1 << " s2=" << s2 << "\n";

    // std::exchange: ganti nilai, kembalikan nilai lama
    int level = 5;
    int lama = std::exchange(level, 10);
    std::cout << "exchange      : lama=" << lama << " baru=" << level << "\n";

    // min, max, dan clamp dari <algorithm>
    std::cout << "min(7, 2)     : " << std::min(7, 2) << "\n";
    std::cout << "max(7, 2)     : " << std::max(7, 2) << "\n";
    std::cout << "min daftar    : " << std::min({5, 1, 9, 3}) << "\n";
    std::cout << "max daftar    : " << std::max({5, 1, 9, 3}) << "\n";
    std::cout << "clamp(150)    : " << std::clamp(150, 0, 100) << "\n";
    std::cout << "clamp(85)     : " << std::clamp(85, 0, 100) << "\n";
    std::cout << "clamp(-12)    : " << std::clamp(-12, 0, 100) << "\n";

    // helper pair: make_pair menduga tipe otomatis
    auto produk = std::make_pair(std::string("kopi"), 18000);
    std::cout << "make_pair     : " << produk.first << " " << produk.second << "\n";

    // swap juga bekerja pada pair: keduanya anggota bertukar sekaligus
    std::pair<int, int> p1 = {1, 2}, p2 = {30, 40};
    std::swap(p1, p2);
    std::cout << "swap pair     : p1={" << p1.first << "," << p1.second
              << "} p2={" << p2.first << "," << p2.second << "}\n";
    return 0;
}

Output yang Dihasilkan:

text
swap int      : x=8 y=3
swap string   : s1=tujuan s2=asal
exchange      : lama=5 baru=10
min(7, 2)     : 2
max(7, 2)     : 7
min daftar    : 1
max daftar    : 9
clamp(150)    : 100
clamp(85)     : 85
clamp(-12)    : 0
make_pair     : kopi 18000
swap pair     : p1={30,40} p2={1,2}

Bedah baris demi baris:

  1. Baris 8-10 (std::swap(x, y)): isi x dan y bertukar — x menjadi 8, y menjadi 3. Untuk std::string di baris 12-14, swap tidak menyalin karakter: kedua string hanya bertukar isi internalnya, sehingga harganya tetap murah seberapa panjang pun teksnya.
  2. Baris 17-18 (std::exchange(level, 10)): fungsi ini melakukan dua hal sekaligus — mengisi level dengan 10 dan mengembalikan nilai lamanya, 5. Variabel lama menangkap nilai lama itu.
  3. Baris 22-23 (std::min, std::max): masing-masing mengembalikan nilai terkecil dan terbesar dari dua argumen. Untuk lebih dari dua nilai, versi dengan daftar kurawal (baris 24-25) memilih dari sekumpulan angka sekaligus.
  4. Baris 26-28 (std::clamp(v, lo, hi)): menjepit v agar tetap dalam rentang [lo, hi] — 150 terpotong menjadi 100, -12 terangkat menjadi 0, dan 85 di tengah rentang tidak tersentuh.
  5. Baris 31-32 (std::make_pair): tipe pasangan diduga otomatis dari argumennya, sehingga cukup auto di sisi kiri — tanpa menulis std::pair<std::string, int> secara eksplisit.
  6. Baris 35-37 (swap pada pair): fungsi generik seperti swap bekerja pada apa pun yang punya tukar-diri, termasuk std::pair — kedua anggota p1 dan p2 bertukar utuh sekaligus.

min, max, dan clamp #

Ketiga fungsi ini mengembalikan referensi ke argumen yang menang, bukan salinan — detail yang membuatnya efisien untuk tipe besar seperti std::string. Ada satu aturan pemisah nilai sama yang jarang diketahui: bila kedua argumen sama, std::min mengembalikan argumen pertama dan std::max mengembalikan argumen kedua. Untuk kebutuhan mengembalikan dua nilai terkecil/terbesar sekaligus, <algorithm> menyediakan std::minmax yang membungkusnya dalam pasangan.

std::clamp(v, lo, hi) sangat praktis untuk validasi rentang: alih-alih menolak input di luar batas, kita menjepitnya kembali ke batas terdekat. Persentase yang masuk sebagai 150 menjadi 100, volume yang dihitung -5 menjadi 0. Satu syarat yang perlu dijaga: argumen lo tidak boleh lebih besar dari hi, karena hasilnya tidak terdefinisi bila urutannya terbalik.

std::exchange dan Pratinjau std::move #

std::exchange(a, baru) adalah cara satu baris untuk “ambil nilai lama, pasang nilai baru”. Pemakaian paling terkenal ada di move constructor — constructor yang mengambil isi objek lain alih-alih menyalinnya. Program berikut adalah pratinjau kecilnya:

cpp
#include <iostream>  // std::cout
#include <string>    // std::string
#include <utility>   // std::exchange, std::move

class Berkas {
public:
    explicit Berkas(std::string isi) : isi_(std::move(isi)) {}

    // pratinjau move constructor: ambil isi objek lain, kosongkan miliknya
    Berkas(Berkas&& lain) noexcept
        : isi_(std::exchange(lain.isi_, {})) {}

    const std::string& isi() const { return isi_; }

private:
    std::string isi_;
};

int main() {
    Berkas sumber("data penting");
    Berkas tujuan(std::move(sumber));  // pindahkan isi, bukan salin

    std::cout << "tujuan : " << tujuan.isi() << "\n";
    std::cout << "sumber : \"" << sumber.isi() << "\" (dikosongkan)\n";
    return 0;
}

Output yang Dihasilkan:

text
tujuan : data penting
sumber : "" (dikosongkan)
  1. Baris 10-11 (Berkas(Berkas&& lain)): parameter Berkas&& disebut rvalue reference — referensi yang menunjuk objek yang isinya boleh dipindahkan. Konsep lengkapnya dibahas tuntas pada Section Move Semantics dan Value Categories; untuk saat ini cukup pahami idiom baris berikutnya.
  2. Baris 11 (std::exchange(lain.isi_, {})): inilah idiom andalannya — dalam satu ekspresi, isi lain.isi_ (teks "data penting") pindah menjadi nilai awal anggota isi_ milik objek baru, dan lain.isi_ diganti dengan string kosong. Tidak ada penyalinan karakter, tidak ada baris yang terlewat.
  3. Baris 21 (std::move(sumber)): std::move tidak memindahkan apa pun; ia hanya menandai sumber sebagai “boleh dipindahkan”, sehingga compiler memilih move constructor di atas. Setelah baris ini, isi sumber secara terkendali menjadi kosong.
  4. Baris 23-24 (hasil): tujuan memegang teks utuh, sumber tercetak kosong — pemindahan selesai tanpa satu karakter pun disalin.

Helper untuk std::pair #

<utility> juga menjadi rumah std::pair beserta pembantunya. std::make_pair(a, b) membentuk pasangan sambil menduga tipenya otomatis — berbeda dengan menulis std::pair<std::string, int> yang menduplikasi informasi yang sudah terlihat dari argumen. Fungsi generik yang sudah kita bahas turut bekerja di sini: std::swap menukar utuh dua pasangan, dan std::min/std::max membandingkan pasangan berdasarkan anggota pertama lalu kedua.

Kumpulan fungsi kecil ini menutup bekal satu per satu: kita kini bisa menukar, mengganti, menjepit, dan membentuk pasangan dengan panggilan pustaka yang idiomatik. Chapter berikutnya adalah penutup Section Standard Library: kita menyusun keputusan — container apa yang tepat untuk tiap kebutuhan dari seluruh container yang sudah kita pelajari.

Rujukan resmi: cppreference — std::swap , cppreference — std::exchange , cppreference — std::clamp .