๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด/C++ ์‘์šฉ

[STL] utility : minmax, move, forward, swap

by ์„œ์•„๋ž‘๐Ÿ˜ 2023. 6. 4.

 

 

# std::minmax

std::min๊ณผ std::max๋Š” ๋งŽ์ด ์จ๋ดค์ง€๋งŒ std::minmax๋Š” ์จ๋ณด์ง€ ์•Š์•˜๋‹ค. ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์€ ์‹ฌํ”Œํ•˜๋‹ค. std::minmax๋Š” std::pair๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š”๋ฐ, ์ฒซ ๋ฒˆ์งธ๊ฐ€ ์ตœ์†Ÿ๊ฐ’, ๋‘ ๋ฒˆ์งธ๊ฐ€ ์ตœ๋Œ“๊ฐ’์ด๋‹ค.

min, max, minmax ๋ชจ๋‘ ๋””ํดํŠธ ์—ฐ์‚ฐ์ž๋Š” '<'์ด์ง€๋งŒ predicate๋ฅผ ํ™œ์šฉํ•ด์„œ ๋‹ค๋ฅธ ๋น„๊ต ์—ฐ์‚ฐ์ž๋ฅผ ์ง€์ •ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

#include <algorithm>
#include <cmath>
#include <iostream>
#include <string>

int main(){

  std::cout << std::endl;

  std::string first{"first"};
  std::string second{"second"};

  auto minInt= std::min({3, 1, 2011, 2014, -5});

  std::cout << "std::min(2011, 2014): " << std::min(2011, 2014) << std::endl;
  std::cout << "std::min(first, second): " << std::min(first, second) << std::endl;
  std::cout << "std::min({3, 1, 2011, 2014, -5}): " << std::min({3, 1, 2011, 2014, -5}) << std::endl;
  std::cout << "std::min(-10, -5, [](int a, int b){return std::abs(a) < std::abs(b);}): "  <<
                std::min(-10, -5, [](int a, int b){return std::abs(a) < std::abs(b);}) << std::endl;


  std::cout << std::endl;

  std::cout << "std::max(2011, 2014): " << std::max(2011, 2014) << std::endl;
  std::cout << "std::max(first, second): " << std::max(first, second) << std::endl;
  std::cout << "std::max({3, 1, 2011, 2014, -5}): " << std::max({3, 1, 2011, 2014, -5}) << std::endl;
  std::cout << "std::max(-10, -5, [](int a, int b){return std::abs(a) < std::abs(b);}): "  <<
                std::max(-10, -5, [](int a, int b){return std::abs(a) < std::abs(b);}) << std::endl;


  std::cout << std::endl;

  auto pairInt= std::minmax(2011, 2014);
  auto pairStr= std::minmax(first, second);
  auto pairSeq= std::minmax({3, 1, 2011, 2014, -5});
  auto pairAbs= std::minmax({3, 1, 2011, 2014, -5}, [](int a, int b){return std::abs(a) < std::abs(b);});

  std::cout << "(pairInt.first, pairInt.second): (" << pairInt.first << ", " << pairInt.second << ")" << std::endl;
  std::cout << "(pairStr.first, pairStr.second): (" << pairStr.first << ", " << pairStr.second << ")" << std::endl;
  std::cout << "(pairSeq.first, pairSeq.second): (" << pairSeq.first << ", " << pairSeq.second << ")" << std::endl;
  std::cout << "(pairAbs.first, pairAbs.second): (" << pairAbs.first << ", " << pairAbs.second << ")" << std::endl;

  std::cout << std::endl;


}

 

 

# std::move

<utility>์— ์ •์˜๋œ std::move๋Š” ๋ฆฌ์†Œ์Šค๋ฅผ ์ด๋™ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์ด๋‹ค. std::move๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์†Œ์Šค(arg)๋ฅผ ์šฐ์ธก๊ฐ’ ์ฐธ์กฐ๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค.

std::move์™€ ์šฐ์ธก๊ฐ’ ์ฐธ์กฐ์— ๋Œ€ํ•ด์„œ๋Š” C++๊ธฐ์ดˆ ์‹œ๋ฆฌ์ฆˆ์—์„œ ๋‹ค๋ฃฐ ์˜ˆ์ •์ด๋‹ค. ์ž์„ธํ•œ ์‚ฌํ•ญ์€ ๋ชจ๋‘์˜์ฝ”๋“œ๋ฅผ ์ฐธ์กฐํ•˜์ž.

https://modoocode.com/301

 

C++ ๋ ˆํผ๋Ÿฐ์Šค - std::move ํ•จ์ˆ˜

 

modoocode.com

 

 

 

# std::forward

std::forward๋Š” ์ฃผ์–ด์ง„ ์ธ์ˆ˜๋ฅผ ๊ทธ๋Œ€๋กœ ์ „๋‹ฌํ•˜๋Š” ํ•จ์ˆ˜ ํ…œํ”Œ๋ฆฟ์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. std::forward๋Š” ํŒฉํ† ๋ฆฌ ํ•จ์ˆ˜๋‚˜ ์ƒ์„ฑ์ž๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐ ์ฃผ๋กœ ํ™œ์šฉํ•œ๋‹ค. 

#include <initializer_list>
#include <iostream>
#include <string>
#include <utility>
#include <vector>

struct MyData{
  MyData(){};
  MyData(int, double, char){};
};

template <typename T,  typename ... Args>
T createT(Args&&...args){
  return T(std::forward<Args>(args)...);
}

int main(){

  int a= createT<int>();
  int b= createT<int>(1);

  std::string s= createT<std::string>("Only for testing purpose.");

  MyData myData= createT<MyData>();
  MyData myData2= createT<MyData>(1, 3.19, 'a');

  typedef std::vector<int> IntVec;
  IntVec intVec= createT<IntVec>(std::initializer_list<int>({1, 2, 3, 4, 5}));

}

ํ•จ์ˆ˜ ํ…œํ”Œ๋ฆฟ์ธ createT๋Š” ์ธ์ˆ˜๋ฅผ ๋ณดํŽธ ์ฐธ์กฐ ํ˜•์‹์ธ 'Arg&&...args'๋กœ ๋ฐ›์•„์•ผ ํ•œ๋‹ค. ๋ณดํŽธ ์ฐธ์กฐ๋ž€ ํƒ€์ž… ์ถ”๋ก ์—์„œ ์šฐ์ธก๊ฐ’ ์ฐธ์กฐ์ธ ๊ฒƒ์„ ๋งํ•˜๋ฉฐ ์ „๋‹ฌ ์ฐธ์กฐ๋ผ๊ณ ๋„ ๋ถ€๋ฅธ๋‹ค. std::forward์™€ ๊ฐ€๋ณ€ ์ธ์ˆ˜ ํ…œํ”Œ๋ฆฟ์„ ์กฐํ•ฉํ•˜๋ฉด ์™„๋ฒฝํ•œ ์ œ๋„ค๋ฆญ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

 

# std::swap

๋‘ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ๋งž๋ฐ”๊พธ๋Š” ์ž‘์—…์„ std::swap์„ ํ†ตํ•ด ์† ์‰ฝ๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‚ด๋ถ€์ ์œผ๋กœ๋Š” std::move๋ฅผ ํ™œ์šฉํ•˜๊ณ  ์žˆ๋‹ค.

#include <algorithm>
#include <iostream>
#include <vector>


template <typename T>
void swap(T& a, T& b){
    T tmp(std::move(a));
    a = std::move(b);
    b = std::move(tmp);
}

struct MyData{
  std::vector<int> myData;

  MyData():myData({1, 2, 3, 4, 5}){}

  // copy semantic
  MyData(const MyData& m):myData(m.myData){
    std::cout << "copy constructor"  << std::endl;
  }

  MyData& operator=(const MyData& m){
    myData= m.myData;
    std::cout << "copy assignment operator"  << std::endl;
    return *this;
  }

};

int main(){

  std::cout << std::endl;

  MyData a, b;
  swap(a, b);

  std::cout << std::endl;

};

 

cppreference์˜ ์˜ˆ์ œ๋ฅผ ๋ณด์ž.

#include <algorithm>
#include <iostream>
 
namespace Ns
{
    class A
    {
        int id {};
 
        friend void swap(A& lhs, A& rhs)
        {
            std::cout << "swap(" << lhs << ", " << rhs << ")\n";
            std::swap(lhs.id, rhs.id);
        }
 
        friend std::ostream& operator<<(std::ostream& os, A const& a)
        {
            return os << "A::id=" << a.id;
        }
 
    public:
        A(int i) : id {i} {}
        A(A const&) = delete;
        A& operator = (A const&) = delete;
    };
}
 
int main()
{
    int a = 5, b = 3;
    std::cout << a << ' ' << b << '\n';
    std::swap(a, b);
    std::cout << a << ' ' << b << '\n';
 
    Ns::A p {6}, q {9};
    std::cout << p << ' ' << q << '\n';
//  std::swap(p, q); // error, type requirements are not satisfied
    swap(p, q);      // OK, ADL finds the appropriate friend `swap`
    std::cout << p << ' ' << q << '\n';
}
// Output
5 3
3 5
A::id=6 A::id=9
swap(A::id=6, A::id=9)
A::id=9 A::id=6

 

๋Œ“๊ธ€