프로그래머/CPP_메모

Uniform Initialization

미역국마싯 2023. 5. 4. 17:44

List-Initialization( 또는 Brace-Initialization )라고도 불리는 것 같다.

 

1. 변수 초기화

int a = 3;    // copy initialization
int a(3);     // direct initialization
int a{3};     // uniform initialization - C++11

변수를 초기화하는 방법은 여러 가지가 있다.

int a = 3.14;    // warning
int a(3.14);     // warning
int a{3.14};     // error

copy와 direct initialization은 암시적 형 변환( implicit type conversion )을 허용한다.

uniform initialization은 암시적 형 변환을 허용하지 않는다.

 

변수 a는 integer인데, 3.14 값을 저장하려고 시도한다.

copy, direct initialization에서는 컴파일러가 implicit type conversion을 시도하기 때문에 3이 변수에 저장된다.

하지만 uniform initialization은 implicit type conversion을 허용하지 않기 때문에 에러가 발생한다.

 

 

2. 클래스 생성자

클래스 생성자에서도 활용할 수 있다.

class Container
{
public:
	Container(unsigned size)
		: _size(size)
	{
		_goods = new int[size];
	}

    // Initializer_list
	Container(const std::initializer_list<int>& l)
		: Container(l.size())
	{
		int count = 0;
		for (auto& e : l)
		{
			_goods[count] = e;
			std::cout << _goods[count] << std::endl;
			++count;
		}
	}
	~Container() { delete[] this->_goods; }

private:
	unsigned _size = 0;
	int* _goods = nullptr;
};

int main()
{
	Container c{ 1, 2, 3 };   // Uniform Initialzation
	Container c2 = { 1, 2, 3 };  // error!, operator= overloading 필수
	return 0;
}

uniform initialization으로 생성자를 호출하면 최우선으로 initializer_list를 파라미터로 가진 생성자를 호출한다.

class Knight
{
public:
	Knight(int hp, int atk, int def)
		: _hp(hp), _atk(atk), _def(def)
	{
		std::cout << _hp << " " << _atk << " " << _def << std::endl;
	}

private:
	int _hp = 50;
	int _atk = 2;
	int _def = 1;
};

int main()
{
	Knight k{ 100, 10, 5 };

	return 0;
}

만약 initializer_list를 파라미터로 가진 생성자가 없다면, 다른 생성자를 overloading 한다.

 

 

3. 함수 인수

함수의 인수에도 사용할 수 있다.

int Sum(const std::initializer_list<int>& l)
{
	int sum = 0;
	for (auto it = l.begin(); it != l.end(); ++it)
		sum += *it;

	return sum;
}

int main()
{
	int s = Sum({ 10, 11, -50, 30, 5 });
	std::cout << s << std::endl;

	return 0;
}

 

 

4. 구조체 초기화

구조체를 초기화할 때도 유용하다.

struct RGBA
{
	float v[4];
};

void Test(RGBA r, int size)
{
	for (int i = 0; i < size; ++i)
		std::cout << r.v[i] << " ";
}

int main()
{
	RGBA{ 0.0f, 0.0f, 0.0f, 1.0f };
    Test(RGBA{ 0.0f, 0.0f, 0.0f, 1.0f }, 4);
}

메모리에 저장될 필요가 없는 임시 데이터를 uniform initialization만 이용해서 처리할 수 있다.

보통 함수의 argument에서 많이 사용한다.

 

 

5. vector에서 헷갈리는 문법

List-initialization은 std::initializer_list를 파라미터로 가진 생성자를 선호한다.

std::vector<int> a(10);
std::vector<int> b{10};

std::vector<int> c(1, 2);
std::vector<int> d{1, 2};

direct-initialization과 uniform-initialization을 vector에 사용하면 다른 결과가 나온다.

 

첫 번째는 vector의 size를 10개로 설정하는 생성자를 호출한다.

두 번째는 vector에 10이라는 element를 저장하는 생성자를 호출한다.

세 번째는 vector의 size를 1로 설정하고, 여기에 element 2를 저장하는 생성자를 호출한다.

네 번째는 vector에 1, 2라는 elements를 저장하는 생성자를 호출한다.

'프로그래머 > CPP_메모' 카테고리의 다른 글

Runtime Error Debugging  (0) 2023.05.04
모듈러 연산( modular, 나머지 )  (0) 2022.04.21
c++ 연산자 오버로딩 정리  (0) 2022.04.03
c++ 배열 정리  (0) 2022.03.21
c++ 참조 정리  (0) 2022.03.20