I'm FanJae.

[C++] 연산자와 제어문 본문

C++/Basic

[C++] 연산자와 제어문

FanJae 2024. 8. 9. 00:11

※ 본 포스트는 코드누리 C++ Basic 강의 내용을 보고 정리한 포스트입니다.

 

- C++에서 새롭게 추가된 for문이 존재한다.

1. range for

 

1-1. std::size() // C++ 17

일반적으로, for를 사용할 때, 배열의 크기가 바뀌면, for 안의 크기도 바뀌어야 했다.

그때 C 언어에서 가장 많이 사용한 방식이 아래 방식이다.

#include <iostream>
int main(void)
{
    int x[10] = {1,2,3,4,5,6,7,8,9,10};
    
    for (int i = 0; i < sizeof(x) / sizeof(x[0]); i++)
    {
    	std::cout << x[i] << ", ";
    }
    
}

 

C++에서는 std::size 라는 것이 존재한다.

#include <iostream>
int main(void)
{
    int x[10] = {1,2,3,4,5,6,7,8,9,10};
    
    for (int i = 0; i < std::size(x) ; i++)
    {
    	std::cout << x[i] << ", "
    }
    
}

- 이와 같이 사용이 가능하다. std::size()는 배열 크기를 구하는 C++ 표준 함수이다.

- 배열 뿐 아니라, C++ 표준 라이브러리(STL)의 다양한 컨테이너의 크기도 구할 수 있다.

 

1-2. range-for // C++ 11

#include <iostream>
int main(void)
{
    int x[10] = {1,2,3,4,5,6,7,8,9,10};
    
    //for ( int e : x ) // range-for
    for ( auto e : x ) // auto로 바꿔주면, x의 데이터 타입이 바뀌는 것에 유연하게 대처할 수 있다.
    {
    	std::cout << e << ", ";
    }
}

- C++11 부터 지원되는 새로운 형태의 for이다.

- 배열 뿐 아니라 다양한 STL 컨테이너도 이를 사용할 수 있다.

- 이는 C++ 뿐 아니라 Python, Java, C# 등에서도 이런 형태의 문법을 확인할 수 있다.

 

1-3. range-for Reverse 

#include <iostream>
#include <ranges>

bool is_odd_number(int n) { return n % 2 == 1; }

int main()
{
	int x[10] = {1,2,3,4,5,6,7,8,9,10};

	for (auto e : x)
	{
		std::cout << e << ", ";
	}
}

- 위 예제는 x를 정방향으로 출력하는 것이다.

- range-for를 이용해서 이를 거꾸로 출력하는 것은 C++ 20 이전에는 별도로 제공하지 않았다.

- C++20부터는 Ranges Library를 사용하여 해결할 수 있다.

- <ranges> 헤더파일을 포함하여, std::views namespace 안에 다양한 함수를 제공한다. 

 

① std::views::reverse

// for (auto e : x)
for (auto e : std::views::reverse(x))

 - for 부분을 위와 같이 수정하면, x의 요소를 하나씩 넣어줄때, 거꾸로 넣어줄 것이다.

 

② std::views::take

// for (auto e : x)
for (auto e : std::views::take(x, 3))

- std::views::take를 이용하면, 지정한 원소 개수만큼만 꺼내는 것도 가능하다.

// for (auto e : x)
for (auto e : std::views::reverse( std::views::take(x, 3)))

- 이와 같이 중첩도 시킬 수 있다.

 

③ std::views::drop

// for (auto e : x)
for (auto e : std::views::drop(x, 3))

drop은 해당 개수만큼 제외하고, 넣으라는 의미가 된다. 

 

④ std::views::filter

// for (auto e : x)
for (auto e : std::views::filter(x, is_odd_number))

- filter는 x에 있는 원소를 차례대로 함수(is_odd_number)에 보내서 참인 값만 반환해준다. 

// for (auto e : x)
for (auto e : std::views::filter(x, [](int n) { return n % 2 == 1; } ) )

Lambda expression을 사용하는 것도 당연히 가능하다.

 

※ Ranges Library에 대한 자세한 내용은 STL에서 다뤄보고자 한다.


2. if with initializer // C++ 17

- C++17 에서는 if 문에 초기화 구문을 넣을 수 있다.

int foo()
{
    return 0;
}
int main()
{
    int ret = foo();
    
    if ( ret == 0 )
    {
    }
    
    // C++17
    if ( int ret = foo(); ret == 0)
    {
    
    }
}

- 이처럼 if문 안에서 초기화 구문 선언이 가능하다.

- 이때의 ret 변수의 수명은 if문 블록을 벗어나는 순간 소멸된다.

switch( int n = foo(); n)
{
  case 1: break;
}

- switch 에서도 사용할 수 있다.

// C++20
for( int x[3] = {1,2,3}; auto n : x)
{

}

- C++20부터는 range - for 도 사용이 가능하다.


3. new

#include <iostream>
#include <cstdlib>

int main()
{
	int* p1 = (int*)malloc(sizeof(int));
	free(p1);

	int* p2 = new int;
	delete p2;

	int* p3 = new int[10];
	delete[] p3;
}

- C 언어에서는 동적 메모리 할당시 malloc 함수를 사용했고, 해제시에는 free를 사용했다.

- C++ 언어에서 이를 사용해도 되나, new와 delete를 이용해 더 간단하게 할당 및 해제가 가능하다.

 

3-1. 동적 메모리 할당 방법

// C
int *p1 = (int *) malloc(sizeof(int));
free(p1);

// C++
int *p2 = new int;
delete p2;

 

3-2. malloc vs new

C malloc new
정체 함수 연산자(키워드)
인자 할당할 메모리 크기 타입
반환타입 void *, 캐스팅 필요 전달 타입의 포인터, 캐스팅 필요 없음.
해지방법 free delete 또는 delete[]
생성자 생성자가 호출 되지 않음 생성자가 호출됨.

- malloc과 new의 결정적인 차이는 생성자 호출 여부에 있다.

 

※ 배열 형태로 메모리를 할당한 경우 반드시 delete[] 로 회수해야 한다. delete로 해지할 경우, undefine(미정의 동작)으로 발생한다.


4. three way comparsion operator // C++20

#include <iostream>

int main()
{
	double n1 = 30, n2 = 20;

	bool b1 = (n1 < n2);


	auto ret = (n1 <=> n2); // C++20 

	if ( ret == 0 )
		std::cout << "n1 == n2" << std::endl;

	else if ( ret > 0 )
		std::cout << "n1 > n2" << std::endl;

	else if ( ret < 0 )
		std::cout << "n1 < n2" << std::endl;

//	std::cout << ret << std::endl;
	std::cout<< typeid(ret).name() << std::endl;

}

- 우주선(spaceship) 연산자라고도 불리는 연산자이다.

- auto ret = (n1 <=> n2); 와 같이 사용한다.

- ret의 비교결과는 다음과 같다.

ret == 0 n1과 n2는 같다.
ret > 0 n1이 n2보다 크다. ( n1 > n2 )
ret < 0 n1이 n2보다 작다. ( n1 < n2 )

 

4-1. <=> 연산자의 반환 타입

- 반환 값을 std::cout로 출력할 수 없다.

- typeid라는 것을 사용하여 타입을 확인할 수 있다.

- 어떤 타입을 비교하는지에 따라 반환 타입이 달라진다. 이 때문에 auto로 받을 수 밖에 없다.

- std::strong_ordering, std::weak_ordering,std::partial_ordering 등으로 나온다.

 

※ 다소 복잡한 얘기가 있어, <=>에 대해서는 추후 별도 포스트로 다루고자 한다.

 

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

[C++] nullptr  (0) 2024.08.11
[C++] Reference  (0) 2024.08.09
[C++] Function III  (0) 2024.08.08
[C++] Function III  (0) 2024.08.08
[C++] Function II  (0) 2024.08.08
Comments