compl

~ 연산자를 대체함

 

explicit

생성자에 붙여 암시적 형변환을 금지하고 명시적 형변환만 가능하게 만드는 용도로 사용한다.

예를 들어 Point p = 10; 의 사용을 금지하고 (int -> Point의 형변환 금지) Point p = Point(10); 만을 사용할 수 있게 한다.

 

extern

다른 파일에 선언된 함수나 변수를 참조하기 위한 용도로 사용 (사용할 전역 변수가 외부 cpp 파일에 있다는 것을 알림)

 

현재 스코프에 사용하고자 하는 함수가 없는 경우 같은 파일 내에서 현재 스코프까지 없는 함수를 참조할 수 있게 해준다.

 

friend

수평적인 클래스 간의 멤버 변수를 공유해야 할 경우 주로 사용된다.

 

private, protected로 선언된 멤버를 외부 클래스에서 접근할 수 있게 해주는 키워드

 

접근 당할 클래스에서 friend 함수, friend 클래스를 선언해주면 외부 함수와 클래스에서 접근 제한자의 영향을 받지 않고 멤버에 접근할 수 있다.

 

mutable

const 함수에서는 원래 멤버 변수의 값을 바꿀 수 없는데 mutable로 선언된 변수의 값은 바꿀 수 있다.

 

volatile

변수의 컴파일러 최적화를 제한하는 용도로 사용 (잘 모르겠음..)

 

typeid, type_info

런타임에 자료형, 개체, 표현식의 형식을 확인할 수 있다.

 

#include <typeinfo>
template < typename T >
T max( T arg1, T arg2 ) {
   cout << typeid( T ).name() << "s compared." << endl;
   return ( arg1 > arg2 ? arg1 : arg2 );
}

typeid() 함수는 추상 클래스 type_info를 구현한 객체를 반환한다.

 

noexcept (C++11)

예외를 발생시키지 않을 함수에 noexcept를 붙인다.

어떤 함수가 절대로 예외를 발생시키지 않는다는 것을 명시하면 컴파일러가 최적화를 수행할 수 있다.

 

noexcept가 붙은 함수에서 예외를 발생시키면 예외가 처리되지 않고 프로그램이 종료된다.

 

C+11부터 소멸자들은 기본적으로 noexcept이기 때문에 소멸자에서 예외를 던지면 안된다.

 

static_cast (C++11)

논리적으로 변환 가능한 타입을 변환한다.

실수 <-> 정수, 열거형 <-> 정수형, 실수 <-> 실수

상속 관계에 있는 포인터 끼리의 변환 (업캐스팅)

 

dynamic_cast (C++11)

안전한 다운 캐스팅을 위해 사용된다.

런타임 시간에 실제로 해당 타입이 다운 캐스팅 가능한지 검사하기 때문에 런타임 비용이 조금 높은 캐스트 연산자이다.

 

reinterpret_cast (C++11)

임의의 포인터 타입끼리 변환을 허용하는 캐스트 연산자

정수 계열 형식이 포인터 형식으로 변환될 수도 있다. (그 반대도 가능)

 

int 변수를 첫 번째 멤버로 갖는 구조체가 있다고 할때 구조체 변수 포인터를 int형 포인터로 형변환하면 int형 변수를 가리키는 포인터가 된다.

 

const_cast (C++11)

const 포인터와 const 레퍼런스의 상수성을 제거하는데 쓰인다.

 

alignof, alignas (C++11)

최신 컴퓨터 하드웨어의 CPU는 데이터 주소가 데이터 크기의 배수일때 효율적으로 메모리를 읽는다.

 

alignas

ㄴ 타입의 정렬 조건을 지정한다.

// alginas(4)와 alignas(alginof(float))은 동일하다.

struct alignas(32) sse_t{ // sizeof(sse_t) = 32, alignof(sse_t) = 32
    float sse_data[4];
}

alignas(64) char cacheline[64]; // alignof(cacheline) = 64

 

alignof(타입)

ㄴ 타입의 맞춤 단위를 반환한다.

 

static_assert (C++11)

컴파일 타임에 assertion을 처리할 수 있다.

템플릿 인자도 constant-expression 범주 안에 들어갈 수 있기 때문에 템플릿을 디버깅하는데 용이하다.

 

더 많은 키워드 확인:

https://docs.microsoft.com/ko-kr/cpp/cpp/keywords-cpp?view=msvc-170 

 

키워드(C++)

C++ 표준 언어 키워드, Microsoft 관련 키워드 및 컨텍스트별 키워드를 나열합니다.

docs.microsoft.com

 

'C++' 카테고리의 다른 글

C++ 동기와 비동기  (0) 2022.08.26
C++ Callable  (0) 2022.08.26
C++ RAII와 스마트포인터  (0) 2022.08.26
C++ 가상 함수, virtual 소멸자, 가상 함수 테이블, 추상 클래스  (0) 2022.08.25
C++ 템플릿, 함수 객체(Functor)  (0) 2022.08.25

C++에서는 시간이 오래 걸리는 작업(파일 읽기)을 쓰레드를 만들어 처리할 수 있다.

프로그램의 실행이 한 갈래가 아니라 여러 갈래로 갈라져서 동시에 진행되는 것을 비동기적 실행이라고 부른다.

 

C++11 표준 라이브러리는 간단한 비동기적 실행을 할 수 있게 해주는 도구를 제공한다.

 

std::promise와 std::future

#include <future>
#include <iostream>
#include <string>
#include <thread>
using std::string;

void worker(std::promise<string>* p) {
  // 약속을 이행하는 모습. 해당 결과는 future 에 들어간다.
  p->set_value("some data");
}
int main() {
  std::promise<string> p;

  // 미래에 string 데이터를 돌려 주겠다는 약속.
  std::future<string> data = p.get_future();

  std::thread t(worker, &p);

  // 미래에 약속된 데이터를 받을 때 까지 기다린다.
  data.wait();

  // wait 이 리턴했다는 뜻이 future 에 데이터가 준비되었다는 의미.
  // 참고로 wait 없이 그냥 get 해도 wait 한 것과 같다.
  std::cout << "받은 데이터 : " << data.get() << std::endl;

  t.join();
}

 

 

future에서 get을 호출하면 설정된 객체가 이동하기 때문에 두 번 호출해서는 안된다.

 

future에 예외도 전달할 수 있다.

 

shared_future

여러 개의 다른 쓰레드에서 future를 get할 필요가 있을 때 사용

future와 달리 복사가 가능하고, 복사본들이 모두 같은 객체를 공유하게 된다.

 

packaged_task

C++에서는 promise-future 패턴을 비동기적 함수(Callable)의 리턴값에 간단히 적용할 수 있는 package_task라는 것을 지원한다.

 

std::async

쓰레드를 명시적으로 생성하지 않아도 됨

std::async에 함수를 전달하면 알아서 쓰레드를 만들어 전달된 함수를 비동기적으로 실행하고, 결과값을 future에 전달함.

 

참조: 

https://modoocode.com/284

'C++' 카테고리의 다른 글

C++ 키워드 정리  (0) 2022.08.27
C++ Callable  (0) 2022.08.26
C++ RAII와 스마트포인터  (0) 2022.08.26
C++ 가상 함수, virtual 소멸자, 가상 함수 테이블, 추상 클래스  (0) 2022.08.25
C++ 템플릿, 함수 객체(Functor)  (0) 2022.08.25

 

C++에서는 ()를 붙여서 호출할 수 있는 모든 것을 Callable이라고 정의한다.

 

Callable 예시

#include <iostream>

struct S {
  void operator()(int a, int b) { std::cout << "a + b = " << a + b << std::endl; }
};

int main() {
  S some_obj;
  some_obj(3, 5); // some_obj는 함수가 아닌 객체 // callable
  
  auto f = [](int a, int b) { std::cout << "a + b = " << a + b << std::endl; };
  f(3, 5); // callable
  
}

 

std::function

Callable들을 객체의 형태로 보관할 수 있는 클래스 std::function

#include <functional>
#include <iostream>
#include <string>

int some_func1(const std::string& a) {
  std::cout << "Func1 호출! " << a << std::endl;
  return 0;
}

struct S {
  void operator()(char c) { std::cout << "Func2 호출! " << c << std::endl; }
};

int main() {
  std::function<int(const std::string&)> f1 = some_func1; // 일반 함수
  std::function<void(char)> f2 = S(); // Functor
  std::function<void()> f3 = []() { std::cout << "Func3 호출! " << std::endl; }; // 람다 함수

  f1("hello");
  f2('c');
  f3();
}

function 객체는 템플릿 인자로 전달 받을 함수의 타입 (리턴 값과 인자)를 받는다.

 

멤버 함수를 가지는 std::function

#include <functional>
#include <iostream>
#include <string>

class A {
    int c;

public:
    A(int c) : c(c) {}
    int some_func(char ch) {
        std::cout << "비상수 함수: " << ++c << std::endl;
        return c;
    }

    int some_const_function() const {
        std::cout << "상수 함수: " << c << std::endl;
        return c;
    }

    static void st() {}
};

int main() {
    A a(5);
    std::function<int(A&, char)> f1 = &A::some_func;
    std::function<int(const A&)> f2 = &A::some_const_function;

    f1(a,'c');
    f2(a);
}

멤버 함수를 function 객체에 담기 위해서는 함수의 원래 인자 앞에 객체를 받는 인자를 추가하면 된다.

멤버함수가 아닌 함수들의 경우 함수의 이름이 함수의 주소값으로 암시적 변환이 일어나지만, 멤버 함수의 주소는 &연산자를 통해 명시적으로 주소값을 전달해줘야 한다.

 

std::bind

원래 함수에 특정 인자를 지정할 수 있다. 첫 번째 인자에 특정한 값을 고정시킨 함수 객체를 만들거나 인자의 순서를 바꾼 함수 객체를 만들 수도 있다.

 

레퍼런스를 인자로 받는 함수에 레퍼런스를 전달하고 싶으면 인자를 std::ref()로 감싸 전달하면 된다.

 

참조:

https://modoocode.com/254

 

RAII (Resource Acquisition is initialization) (자원 획득은 초기화와 같다)

자원의 안전한 사용을 위해 객체가 쓰이는 스코프를 벗어나면 자원을 해제해주는 패턴

heap에 할당된 자원은 명시적으로 delete 해주지 않으면 해제되지 않지만 stack에 할당된 자원은 범위를 벗어나면 메모리가 해제되며 소멸자가 불리는 원리를 이용한 것이다.

 

스마트 포인터(포인터 객체)의 종류 

1. unique_ptr 

C++에서 메모리를 잘못된 방식으로 관리했을 때 생기는 두 가지 문제 

 

1. 메모리 할당 후 해제하지 않아 메모리 누수가 생기는 경우

ㄴ RAII 패턴으로 해결 가능

 

2. 이미 해제한 메모리를 참조하는 경우

ㄴ 여러 개의 포인터가 같은 객체를 두번 해제하는 경우가 발생할 수 있다.

ㄴ 이미 해제한 객체를 참조할 가능성도 있다.

ㄴ unique_ptr로 해결 가능

 

// 함수 내에 정의(스택에 정의)된 객체이기 때문에 함수가 종료될 때 소멸자가 호출되고,
// 소멸자 안에서 자신이 가리키고 있는 자원 (A)를 해제해 준다.
std::unique_ptr<A> pa(new A());

// unique_ptr은 -> 연산자를 오버로드해서 포인터를 다루는 것처럼 함수를 호출할 수 있다.
pa->some();

 

unique_ptr 객체는 복사할 수 없지만, 소유권을 이전할 수 있다.

 

ㄴ unique_ptr의 복사 생성자는 delete 키워드로 명시(사용 금지) 하였기 때문에 하나의 자원(객체)를 여러 unique_ptr이 소유하지 않도록 한다.

 

std::unique_ptr<A> pb = std::move(pa);

ㄴ unique_ptr의 이동 생성자는 정의되어 있다. (자원의 주소를 단순 복사하는 형태로?)

ㄴ 이 문장이 실행된 이후 pa는 댕글링 포인터 (해제된 메모리 영역을 가리키는 포인터)가 되므로 참조해서는 안된다.

 

unique_ptr을 함수 인자로 전달하기

unique_ptr의 레퍼런스를 전달하는 경우

ㄴ unique_ptr의 의미가 퇴색된다. (컴파일 오류는 없으나 함수 안에서는 두 개의 이름(스마트 포인터)로 자원을 가리키기 때문)

 

대신에 자원의 포인터 주소값을 전달하자

ㄴ unique_ptr의 get() 함수는 자원의 포인터 주소를 반환하는데 이것을 함수에 전달하면 된다.

 

unique_ptr을 make_unique로 생성하기

C++14 부터는 make_unique를 사용하여 unique_ptr을 만들 수 있다.

// 기존 방법
std::unique_ptr<Foo> ptr(new Foo(3, 5));

// make_unique를 사용하는 방법
auto ptr = std::make_unique<Foo>(3, 5);

 

unique_ptr를 원소로 가지는 컨테이너

std::vector<std::unique_ptr<A>> vec;
std::unique_ptr<A> pa(new A(1));


// vector의 push_back에 pa를 넘겨주면 좌측값 레퍼런스로 인식하여 복사 생성자를 호출하기 때문에
// 컴파일 에러가 난다.
vec.push_back(pa); 

// 우측값 레퍼런스를 받도록 오버로딩된 push_back을 호출하기 위해 move()를 사용한다.
vec.push_back(std::move(pa));

// emplace_back을 사용하면 벡터 안에 unique_ptr을 생성과 동시에 집어넣을 수 있다.
// vec.push_back(std::unique_ptr<A>(new A(1))); 과 동일
vec.emplace_back(new A(1));

 

2. shared_ptr

ㄴ 하나의 자원을 여러개의 객체에서 사용하는 상황에서 자원을 해제 하기 위해서는 모든 객체를 소멸시키고 자원을 해제해야 한다. (= 여러 개의 스마트포인터 객체가 같은 객체를 가리킬 수 있다)

std::shared_ptr<A> p1(new A());
std::shared_ptr<A> p2(p1);  // p2 역시 생성된 객체 A 를 가리킨다.

p1.use_count(); // 2
p2.use_count(); // 2

 

스마트 포인터의 참조 개수가 몇개 인지 어떻게 확인하는가?

ㄴ shared_ptr은 복사 생성될 때 제어 블록의 위치(참조 개수를 알고 있는 블록)을 공유한다.

 

첫 shared_ptr을 만들 때는 자원의 동적할당과 제어 블록의 동적할당이 필요하다.

 

shared_ptr을 make_shared로 생성하기

make_shared 함수는 자원과 제어 블록의 동적할당을 따로 두 번 하지 않고 한 번의 동적할당으로 처리한다.

std::shared_ptr<A> p1 = std::make_shared<A>();

 

shared_ptr 생성 시 주의 할 점

 

shared_ptr을 자원의 주소 값으로 생성하면 무조건 제어 블록을 생성한다. (첫 번째로 생성된 shared_ptr의 경우는 괜찮지만 두 번째 이상 부터는 두 개 이상의 제어 블록이 생기는 결과를 낳는다.) 첫 번째와 두 번째로 생성된 shared_ptr들 모두 제어 블록을 따로 가지며, 각자 자원에 대한 참조 개수가 1로 알고 있기 때문에 둘 중 하나의 shared_ptr이 소멸될 때 자원도 같이 소멸된다. (참조 개수가 0이 되면 자원도 소멸시키므로)

 

enable_shared_from_this

this를 사용해서 shared_ptr을 만들고 싶은 클래스가 있다면 std::enabled_shared_from_this를 상속받으면 된다.

class A : public std::enable_shared_from_this<A> {
  
  // 이미 정의되어있는 제어 블록을 사용해서 shared_ptr을 생성한다.
  // 즉 이미 이 객체에 대한 shared_ptr가 만들어져 있어야 한다.
  
  std::shared_ptr<A> get_shared_ptr() { return shared_from_this(); }
}

 

shared_ptr의 순환참조 문제와 3. weak_ptr

 

shared_ptr을 멤버로 갖는 객체를 서로 참조하고 있는 상태 : 순환 참조 상태

 

class A {
  std::string s;
  std::weak_ptr<A> other; // std::shared_ptr<A> other 순환 참조를 일으키는 shared_ptr 대신 사용
}

week_ptr은 이미 만들어진 shared_ptr나 week_ptr로부터만 생성될 수 있다. (생성자로 받는다.)

week_ptr은 참조 개수를 늘리지는 않는다.

week_ptr로 객체를 참조하기 위해서는 lock()함수를 사용하여 shared_ptr로 변환해야 한다.

week_ptr이 가리키고 있던 객체가 소멸되었다면 (shared_ptr이 가리키지 않아서) lock()은 빈 shared_ptr을 반환하고

가리키고 있던 객체가 아직 shared_ptr에 의해 가리켜지고 있다면 객체를 가리키는 shared_ptr을 반환한다.

 

객체는 해제되어도 제어 블록은 해제되면 안되는 경우

ㄴ 객체를 가리키는 shared_ptr은 0개이지만, week_ptr이 남아 있는경우

ㄴ 제어 블록을 해제하기 위해서는 week_ptr도 0개여야 한다.

 

제어 블록에는 참조 개수와 더불어 약한 참조 개수도 기록되어 있다.

 

참조:

https://modoocode.com/252

 

동적 바인딩 (virtual 키워드를 사용할 경우 vtable을 통해 구현됨)

ㄴ 런타임에 어떤 함수가 호출될지를 정함

 

정적 바인딩 (virtual 키워드 쓰지 않은 함수)

ㄴ 컴파일 타임에 어떤 함수가 호출될지를 정함

 

override 키워드

C++11 에서부터 파생 클래스에서 기반 클래스의 가상 함수를 오버라이드 하는 경우 override 키워드를 통해 명시적으로 나타낼 수 있음

 // 기반 클래스
 virtual void what() { std::cout << s << std::endl; }
 
 // 파생 클래스
 void what() override { std::cout << s << std::endl; }

 

virtual 소멸자

// 부모 클래스의 소멸자에 virtual을 붙이지 않는 경우

// parent 생성자 - child 생성자 - child 소멸자 - parent 소멸자 순으로 정상적으로 호출된다.
Child *c = new Child();
delete c;

// parent 생성자 - child 생성자 - parent 소멸자 순으로 호출된다.
// 자식 클래스의 소멸자가 호출되지 않는다.
Parent *p = new Child();
delete p;

소멸자가 호출되지 않는 문제는 Child 객체의 생성자에서 멤버 변수들을 위해 메모리를 동적 할당했을 경우 메모리 누수로 이어질 수 있다.

 

가상 함수의 구현 원리 (vtable), 가상 함수의 오버헤드

가상 함수가 하나라도 존재하는 클래스의 객체의 가장 윗 부분에는 vtable의 주소값이 저장되어 있다. (x64 에서는 8byte)

포인터가 아닌 실제로 가리키고 있는 객체(클래스)의 vtable을 참조한다. 

자식 클래스의 vtable은 부모 클래스의 vtable값이 그대로 복사되며, 오버라이딩 된 함수만 주소가 새로 업데이트된다.

vtable에는 virtual로 선언된 가상 함수만 저장된다.

vtable은 클래스 단위로 만들어진다. (만들어지는 객체의 개수와 관련이 없다)

 

일반 함수를 호출하는 경우 함수는 바로 호출되지만

가상 함수를 호출하는 경우 가상 함수 테이블을 한번 거쳐서 함수를 호출하기 때문에 시간이 더 오래 걸린다. (오버헤드)

 

순수 가상함수와 추상 클래스

순수 가상함수를 한 개 이상 가진 클래스를 추상 클래스라고 한다.

class Animal {
 public:
  Animal() {}
  virtual ~Animal() {}
  // 순수 가상 함수 // 반드시 오버라이딩 되어야 하는 함수
  virtual void speak() = 0;
};

 

참조:

https://modoocode.com/210

'C++' 카테고리의 다른 글

C++ Callable  (0) 2022.08.26
C++ RAII와 스마트포인터  (0) 2022.08.26
C++ 템플릿, 함수 객체(Functor)  (0) 2022.08.25
C++ r-value 참조와 move, 이동 생성자  (0) 2022.08.25
C++ 문자열 처리  (0) 2022.08.24

 

클래스 템플릿 정의

클래스 정의 위에 

template <typename T>

template <class T>

둘 중 하나를 붙여 템플릿을 정의한다.

 

템플릿은 인스턴스화 되기 전까지는 컴파일 시에 아무런 코드로 변환되지 않는다.

= 템플릿은 컴파일 시에 인스턴스화 된다.

 

템플릿 특수화

template <typename T>
class Vector {
  T* data;
  int capacity;
  int length;
}

// 템플릿 특수화 bool을 템플릿 인자로 전달하는 경우
template <>
class Vector <bool>{
  unsigned int* data; // bool* data로 쓰게 되면 원소 하나당 1byte씩 쓰기 때문에 1bit로 표현하기 위함이다.
  int capacity;
  int length;
}

 

함수 템플릿

template <typename T>
T max(T& a, T& b) {
  return a > b ? a : b;
}

int main(void){
  int a = 3;
  int b = 5;
  cout << max(a, b); // C++ 컴파일러가 max<int>(a, b)로 인식하여 처리해줌
}

 

 

함수 객체(Functor)

ㄴ 함수는 아니지만 operator()를 내부에 구현하여 함수인척 하는 객체

ㄴ sort 함수에 템플릿 인자로 넣어 오름차순, 내림차순을 설정할때 사용하기도 한다.

 

타입이 아닌 템플릿 인자

template <typename T, int num>
T add_num(T t) {
  return t + num;
}

템플릿 인자로 전달할 수 있는 타입들은 제한적이다.

ㄴ 정수 타입, (float, double) 제외

ㄴ 포인터 타입

ㄴ enum 타입

ㄴ 널포인터 (std::nullptr_t)

 

예시) 함수를 배열을 전달할 때 배열의 크기를 잃어버린다는 문제가 있었는데, C++11의 std::array를 사용하여 배열을 생성할 경우 템플릿 인자로 배열의 크기를 명시할 수 있게 되었다.

std::array<int, 5> arr = {1, 2, 3, 4, 5};

// arr.size()로 배열 크기에 대한 정보 획득 가능

 

디폴트 템플릿 인자

template <typename T>
struct Compare {
  bool operator()(const T& a, const T& b) const { return a < b; }
};

template <typename T, typename Comp = Compare<T>>
T Min(T a, T b) {
  Comp comp;
  if (comp(a, b)) {
    return a;
  }
  return b;
}

// Min함수 템플릿은 피연산자로 정수가 오든 문자열이 오든 처리가 가능하다

 

참조:

https://modoocode.com/219

 

l-value는 어떠한 메모리 위치를 가리키는데, & 연산자를 통해 그 위치를 참조할 수 있다.

r-value는 l-value가 아닌 값들, 대입 시 오른쪽에만 올 수 있는 value들이다. (임시 객체, 함수가 반환하는 객체, move()가 반환하는 값 등)

 

표현식 이후에 사라지면 r-value 사라지지 않으면 l-value

 

l-value reference 는 &하나로 정의

 

1. void foo(X&); 만 구현했을 경우

ㄴ foo는 좌측값만 인자로 받을 수 있다.

 

2. void foo(X const&);만 구현했을 경우

ㄴ foo는 좌측 값과 우측 값을 인자로 받을 수는 있지만 우측값일 때를 구별할 수가 없음

 

3.void foo(X &) or void foo(X const &); 와

   void foo(X &&); (우측 값만 받음) 모두 구현해야 구분할 수 있다.

 

우측값 참조라 선언되었더라도 이름이 있다면 좌측값 없다면 우측값이다.

예시 1.

void foo(X&& x) {
  X anotherX = x;  // x가 우측값 레퍼런스로 정의되었고 이름이 있기 때문에 좌측값이다. X(X const & rhs) 가 호출됨
}

 

예시 2.

X&& goo();
X x = goo();  // 이름이 없으므로 우측값. 즉 X(X&& rhs) 가 호출됨

 

std::move()

ㄴ 레퍼런스를 인자로 받고, 이것을 우측값 참조로 리턴하는 함수 (이름을 없애는 함수? 우측 값으로 바꿔주는 함수? 임시 객체를 리턴하는 함수?)

 

이동 생성자

MyString::MyString(MyString &&str) {
  std::cout << "이동 생성자 호출 !" << std::endl;
  string_length = str.string_length;
  string_content = str.string_content;
  memory_capacity = str.memory_capacity;

  // 임시 객체 소멸 시에 메모리를 해제하지
  // 못하게 한다.
  str.string_content = nullptr;
}


MyString::~MyString() {
  // 임시 객체의 string_content가 nullptr(0)이면 string_content를 해제하지 않는다.
  if (string_content) delete[] string_content; 
}

MyString str3 = str1 + str2; // operator+함수로 리턴된 임시 객체는 우측 값이다.

 

객체를 STL 컨테이너에 넣을 때, 이동 생성자 작성 시 주의할 점

STL 컨테이너들은 이동 생성자에서 예외가 발생했을 때 처리할 수 없기 때문에 이동 생성자를 noexcept로 명시하지 않으면 이동 생성자 대신 복사 생성자를 사용한다.

 

참조:

https://modoocode.com/227

 

string 클래스

string 생성

string str; string

str = "abcdef";

string str("abcedf");

string *str = new string("abcdef");

string str1(str2);

string 연산

string 객체 간에 >, <, ==, + 연산자를 사용할 수 있다.

>, < 는 사전 순 비교, ==는 동일 여부 확인

+는 문자열 연결

 

string 클래스의 멤버 함수

str.at( index ) : index번째 문자 반환 (유효한 범위인지 체크)

str[ index ] : index번째 문자 반환 (유효한 범위인지 체크X, at보다 빠름)

str.front() : 가장 앞 문자 반환

str.back() : 가장 뒤 문자 반환

str.c_str() : string 문자열을 const char* 로 접근할 수 있도록 해줌 ('\0' 포함)

 

str.length() : 문자열 길이 반환

str.size() : 문자열 길이 반환

str.capacity() : 문자열이 사용중인 메모리 크기 반환

str.resize(n) : string의 길이(용량 X)를 n으로 바꿈

str.reserve(n) : n만큼의 메모리를 미리 할당해줌

str.shrink_to_fit() : capacity를 문자열 길이에 맞게 조절해줌 (정확하게 길이와 일치하지는 않음)

 

str.append(str2) : 문자열을 이어 붙임 ('+' 연산과 동일)

str.insert(n, str2) : n번째 index 앞에 str2 문자열을 삽입

str.repleace(n, k, str2) : n번째 index부터 k개의 문자를 str2로 대체함

str.clear() : 문자열 지우기 (str이 size가 0인 문자열이 됨)

str.erase(n, m) : n ~ m index의 문자열을 지움

 

str.compare(str1) : str이 str1보다 더 크면 1을 반환, 같으면 0, 작으면 -1을 반환 ( 크기 비교는 숫자 < 대문자 < 소문자 )

str.find(str1) ,str.find (c) : 문자열 내에서 문자열이나 문자를 검색해 index를 반환 ( 없으면 -1을 반환)

 

참조 : 

https://rebro.kr/53

'C++' 카테고리의 다른 글

C++ 템플릿, 함수 객체(Functor)  (0) 2022.08.25
C++ r-value 참조와 move, 이동 생성자  (0) 2022.08.25
C++ memory order, atomic객체  (0) 2022.08.24
C++ thread, mutex, condition_variable  (0) 2022.08.23
C++ STL 컨테이너 정리  (0) 2022.08.22

+ Recent posts