C++/문법/자료형

덤프버전 :

파일:나무위키+넘겨주기.png   관련 문서: C++

파일:나무위키+상위문서.png   상위 문서: C++/문법



1. 개요
2. 원시 자료형 (Primitives)
3. 자료형 한정자 (Type Qualifier)
3.1. const
3.2. volatile
3.3. 포인터
3.4. 좌측 참조자
3.4.1. const&
3.5. 우측 참조자
4. auto
5. using
6. decltype
6.1. decltype(auto)
6.2. decltype(expression)
7. 값 범주 (Value Category)
7.1. lvalue
7.1.1. 문자열 리터럴
7.2. prvalue
7.3. xvalue
7.4. glvalue (lvalue & xvalue)
7.5. rvalue (prvalue & xvalue)



1. 개요[편집]


C++의 자료형에 관해 포괄적으로 설명하는 문서.


2. 원시 자료형 (Primitives)[편집]


C언어의 자료형을 그대로 사용할 수 있다. C17까지는 C언어에서 진리값(
bool
[1])을 사용하려면
를 삽입하고
_Bool
, 0, 1을 써야 했으나 C23에서
bool
,
true
,
false
가 정식으로 편입되면서 원시 자료형에서는 C와 C++의 차이가 아예 사라졌다. C에서 파생 자료형으로 제공되던
size_t
,
rsize_t
,
ptrdiff_t
도 제공한다.



C++에서는 1이 참(True), 0이 거짓(False)로 대응되는 것이 기본적인 사용법이나, 0이 아닌 숫자가 대입된다면 사실상 전부 True로 인식되는 탓에, 모든 숫자가 1로 바뀌어 출력된다.
import <iostream>; // C++17 까지는 #include <iostream>

int main()
{
    bool a = 20, b = 0, c = -2;
    std::cout << a << "," << b << "," << c;
    return 0;
} 
해당 코드를 실행시켜보면 출력 결과가 1,0,1임을 확인할 수 있다.


3. 자료형 한정자 (Type Qualifier)[편집]



3.1. const[편집]


상수 (Constant). 다른 자료형 앞에 붙어 값이 불변함을 나타낸다. 가령
const int
는 변하지 않는 정수 값임을 의미한다. 사용자 단에서는 변수 선언 시, 함수의 결과값을
const
로 표시하여 그 값을 변경하지 말라는 지시 효과를 볼 수 있다. 함수 구현 시에는 매개 변수에 붙여 약간의 최적화를 기대하거나, 또는 참조자 변수에 붙여 매개변수가 가리키는 값을 수정하지 말라고 지시를 내릴 수 있다. 사용자의 실수를 줄이고 예측할 수 없는 값의 수정을 막아준다.
만약 포인터와 조합했을때는 포인터가 가리키는 값이 불변인지, 아니면 포인터 자체가 불변인지가 달라진다. 전자는
*ptr
로 값을 접근한 값이
const
이고, 후자는
ptr
자체가 불변이지만
*ptr
로 접근한 값은 바꿀 수 있다. 예를 들어
const char* string
은 변하지 않는 문자값의 포인터를 의미한다. 그러나 포인터가 아니라 문자의 값이 상수이기 때문에 변수
string
에 1을 더하고 빼는 등 값을 변경할 수 있다. 표준 라이브러리에서는 이를 이용해 자료구조 뿐만 아니라 문자열에 대해서도 똑같이
에서 연산을 지원한다. 반면
char* const& string
이라면
string
이 가리키는
char*
값 하나는
*string = 'B';
처럼 언제든지 값이 바뀔 수 있다. 그러나
string
포인터는 불변이다. 사실 상수 포인터, 상수를 가리키는 포인터는 현재 C++에서는 고려할 필요가 없다. C++17에서
string_view
,
span
의 도입으로 웬만한 포인터 사용을 대체할 수 있기 때문이다 [2]. 이해하기 어렵다면 다른 자료형 앞에 붙어야 의미가 있다는 것을 기억하자.


3.2. volatile[편집]


휘발성 (Volatile). 다른 자료형 앞에 붙어 값에 대해 최적화를 막고 항상 값이 보이도록 한다. 컴파일러는 바이너리를 구축하는 과정에서 인라이닝, 캐싱, 파이프라인 분기 예측, 상수식 평가 등을 동원해 가장 빠르고 작은 크기의 바이너리를 만든다. 최적화를 하는 과정에서 몇가지 변수와 상수 표현식으로 선언된 상수는 없어진다. 컴파일 시간에 평가할 수 있는 구문은 미리 작성한다. 그리고 평가되지 않을 구문 역시 아예 코드에서 배제된다. 심지어는 메서드의 존재 자체가 없어지고 모든 쓰임새가 반환값으로 대체될 수도 있다. 예를 들어 어떤 동일한 for문이 여러 곳에서 반복된다면 for문의 내용을 진짜 반복하는 대신에 결과를 미리 계산해놓고 가져다 쓸 것이다.

이 과정은 거의 대부분의 경우 이득을 가져다 주지만, 변수의 존재 삭제와 구문 단축이 문제가 된다. 어떤 값이
true
라면 오류가 떠서
while(bool 변수);
로 문맥 흐름을 막았다고 해보자. 그럼 당연하게도 안의
bool
변수가 다른 스레드에서
false
로 바뀌면 무한 루프를 빠져나갈까? 정답은 그렇지 않다. 계속 갇혀있다. 왜냐하면
while
안의 변수는 최적화를 위해 메모리를 읽지 않고 컴파일 순간 정해진 캐시의 값을 계속 가져오기 때문이다. 또다른 예로는 프로그램 내내 같은 주소를 가리키는 포인터의 값을 읽을 필요가 있다고 해보자. 이러면 컴파일러는 컴파일 당시에 해당 포인터가 가리켰던 값만을 가져온다. 그래서 해당 포인터가 가리키는 값이 변경되어도 프로그램에선 바뀐 값을 알지 못한다. 바로 이럴때
volatile
을 자료형 앞에 붙여서 캐시말고 항상 메모리에서 가져오도록 만들 수 있다. 즉 휘발성이라는 말은 현재 변수에서 읽은 값이 임시적이라는 의미다.

한편
volatile
의 특성은 단일 스레드에서만 적용된다. 컴파일러의 인위적인 코드 패치 순서 수정, 파이프라인 최적화를 막지만, 단일 스레드에서만 그렇다. 다중 스레드를 사용할 때는 여전히 값 읽기 쓰기 순서에 따른 문제가 발생할 수 있다. 이에 대해서는 원자적 메모리를 참고하라.


3.3. 포인터[편집]


*를 다른 자료형 뒤에 붙어 값이 포인터임을 나타낸다.


3.4. 좌측 참조자[편집]


& 참조.
type& identifier = value;
와 같이
&
를 다른 자료형 뒤에 붙여 값이 참조 형태임을 나타낸다. 가령
int&
는 다른 정수를 참조하는 변수임을 의미한다. 함수의 매개변수에서도 똑같이 사용한다. 변수에 값을 할당하거나, 바꾸거나, 얻는 경우 다른 접두사, 접미사 없이 변수의 이름만 사용한다. C++에서 참조한다는 것은 해당 변수가 스스로 값을 가지지 못하고, 다른 변수의 값을 가리킨다는 의미이다. 이런 점에서 참조 변수는 다른 변수의 별칭(Alias)이라고 볼 수 있다.
int original_v1 = 1'000'000;
int original_v2 = 7'000'000;
int original_v3 = 9'000'000;

int& ref_v1 = original_v1;
int& ref_v2 = original_v2;
int& ref_v3 = original_v3;

ref_v1 = 1000; // original_v1의 값이 1000이 된다.
int* handle_v1 = &ref_v1; // original_v1의 주소를 가져온다.

ref_v1 = original_v2; // 가리키는 변수가 바뀌지 않는다. original_v1의 값이 7000000이 된다.
ref_v1 = ref_v2; // 둘 다 가리키는 변수가 바뀌지 않는다. original_v1의 값이 7000000이 된다.
*handle_v1 = original_v3;// 가리키는 변수가 바뀌지 않는다. original_v1의 값이 9000000이 된다.

const int original_c = 1'000'000;
const int& ref_c = original_c; // 상수 변수는 상수 참조형으로 받아야 한다.

그러면 C의 포인터랑 대체 다른 것이 뭔가? 라면 일단 일반 사용자 단에서는 변수를 사용할 때
(*handle)
이나
handle->...
을 사용하지 않아도 된다. 메모리에 대해 조금 알고 있다면 포인터처럼 임의 주소 참조나 보안 문제가 없을 거라는 예상을 할 수 있다. 그러나 깊게 파고들어가면 아주 이상한 특징이 있다. 참조자는 값이 아니다. 라는 것을 명심해야 한다. 참조 변수 자체는 어떤 주소, 고유한 값을 가지지 않는다. 즉 참조 변수는 스스로 존재할 수 없다[3]. 바로 이름만 가진 변수다. 만약
&
연산자를 변수 앞에 붙여 주소를 얻으면 참조 변수의 주소가 아니라, 가리키는 변수의 주소가 나온다. 주소를 가져오는 표준 라이브러리의
std::addressof
함수를 사용해도 마찬가지다. 그래서 참조 변수는 명백하게 존재하고 여기저기 갖다 쓸 수 있지만 참조 변수가 가리키는 어떤 변수만 조작할 수 있을 뿐, 정작 참조 변수 자체는 건드릴 방법이 없다.


3.4.1. const&[편집]


한편 좌측 참조자의 또다른 용도는 C++안에 있는 모든 유형의 값을 전부 담을 수 있다는 것이다. 복사나 어떤 오버헤드 없이 그냥 원래 변수에 다른 이름을 붙여주었을 뿐이기 때문이다! 때문에 복사 불가능한 클래스, 이동 불가능한 클래스, 크기가 4GB짜리인 배열 등도 아무런 문제가 없다. 이는 일반적으로 생각하는 클래스같은 복합 자료형에만 적용되지 않는다.
const&
는 독특하게 어떤 값이던 대입할 수 있다. 가령
const int& power = 9000;
,
struct A{}; const A& aaa = {};
처럼 그 어떤 값도 담을 수 있다. 어떻게 가능한 것일까?

C++에서 참조 변수를 쓴다는 것은 변수에 다른 이름을 붙여주는 것이라고 앞에서 설명했다. 그런데
9000
같은 값은 이름이 없는 임시 값이다. 원래 이 값들은 우측값 (Right-Value)이라고 부르는 값이였다. 전통적으로 C언어에서는 임시 값이 선언, 대입, 비교문에서 식의 오른쪽에 놓이는 경향이 있어서 이렇게 지칭되어 왔다 [4]. 그런데 C에서 포인터로 행하던 복사 없는 일관성있는 참조가 C++의 & 참조 하나만으로는 불가능하다는 문제가 있었다. 만약 어떤 함수에서 정수, 구조체 변수를 참조한다고 했을때 포인터 방식에서는 포인터 매개변수를 써서 오버로딩을 통해 적어도 일관성있는 함수들을 만들 수 있다. 정수의 경우 변수를 하나 만들어야 하겠지만 말이다. 그런데 참조 변수를 만들어서 문제 많은 포인터를 대체하려고 했더니, 여전히 똑같은 짓을 해야한다는 문제가 있었다. 아직도 정수 그대로를 함수에 전달할 수 없었다. 그래서 C++11에서 우측값이 추가되며
const&
한정자는 임시 객체에 이름을 붙여주고
&&
로 표현되는 임시 객체를 참조할 수 있게 되었다. 여전히
&
참조 변수는 이것이 불가능하다. 당장
int& value = 9000;
따위는 오류가 발생한다. 이에 대한 설명은 값 범주 단락에서 후술.


3.5. 우측 참조자[편집]


&& 참조. C++11에서 추가된 핵심 문법이다.
&&
는 해당 변수를 가감없이 그대로 전달한다는 의미가 있다. 그래서
&&
의 다른 이름은 이동 참조자라고도 한다. 컴파일러에게 메모리의 중복 할당을 방지하며 재사용을 지시하고, 값의 깊은 복사를 막는 역할을 한다. C언어에서 깊은 복사를 막기 위해 메모리 풀링, 포인터 사용을 오랜 세월 해왔다. C++의 참조자 역시 최대한 얕은 복사로의 유도를 했을 뿐, 어쩔 수 없이 임시 객체 생성, 변수의 중복 선언 등으로 인한 오버헤드가 있었다. 시스템 자원의 중복도 큰 문제가 되었다. 가령 스레드, 뮤텍스, GDI 객체, 핸들은 시스템에서 생성되고 관리된다. 사용자는 운영체제 호출을 통해 간접적으로 제어할 수 있다. 그런데 생성, 제어는 그렇다 치고 이 중복된 자원들이 파괴되는 경우가 있을 것이다. 이때 다른 곳에서 핸들이 파괴된 일을 모르면 잘못된 운영체제 호출이 발생하고, 이 오류는 단순한 런타임 오류와는 궤를 달리할 것이다.

중요한 것은
&&
는 사실 여전히 참조형이다. 그럼
&&
이 참조하는 원본이 있을 건데 어떻게 되는가 하면, 이동 연산이 목표로 하는 메모리에 바로 전달된다. 또한
&&
변수의 이름 자체도 아무런 의미가 없다. 사용자가 직접
&&
자료형을 명시하던가, 아니면 함수의 도움 없이는 C++에서
&&
는 항상
&
로,
const&&
는 항상
const&
로 연역된다.
&&
&
보다 더 불안정해서, 존재가 바스라지는 존재다.

&&
는 중복 자원의 문제도 깔끔하게 해결한다. 기존에는 한정자 없는 생성자와
const&
생성자 뿐이었고, 이를 본질적으로 구분할 수 없다는 문제가 있었다. 이는
const&
인지
&
인지는 아무 상관이 없다. 생성할 때 변수에 넣지 않고
CThread work_thread{CThread{ th_id, x, y }};
처럼 시스템 자원 객체를 바로 전달받아도 복사 생성자에서 필연적으로
const CThread&
임시 객체가 생성되버린다. 이때 보이지 않는
const CThread&
객체는
work_thread
에 시스템 자원을 순순히 넘겨주는 것처럼 보여도, 만약 소멸자에서 시스템 자원을 해제하도록 했다면
work_thread
는 생성하자마자 죽은 객체가 된다. 이를 막으려면 두가지 방법이 있는데, 임시 객체인지 표시하는 플래그를 넣던가, 자원을 해제하는 전역 함수를 별도로 만들어야 하는데, 모두 최적화, 깔끔함 둘 다 만족시키지 못한다.
&&
&
만 붙이면 신경쓸 필요가 없는 참조형과는 다르다. &를 하나 더 붙여 컴파일러와 사용자에게 복사, 참조와는 구분하게 하고 있다. 객체를 생성하는 방법을 하나 더 제시함으로써 많은 문제가 해결된 것이다.

사실
&&
는 입문 시기에는 직접 쓸 필요가 없다. 컴파일러가 알아서 복사, 이동 생성자를 만들어주니까. 그러나 진도를 조금만 넘겨도 혜성처럼 등장하고, 고급 단계에서는 이해하지 못하면 C++의 알 수 없는 기전에 좌절할 수 있다. C++의 표준 라이브러리에서는
모듈의
std::move
라는 함수로 간편한 이동 연산을 제공한다. 또는 사용자가 직접
static_cast(value)
로 지시할 수 있다.


4. auto[편집]


C++에서 일반 사용자가 가장 유용하게 사용할 수 있는 기능 중에 하나다. C++에서 극히 희귀한 문법적 설탕 요소이며 자료형을 일일이 명시해야하는 문제를 해결하기 위해 도입되었다. 사용법은 간단하게 변수와 함수에서 자료형을 작성할 때 대신
auto
를 기입하면 된다. 컴파일러가 해당 변수, 함수의 반환형을 추론하여 바이너리에 알아서 반영해준다. 라이브러리를 직접 작성하는 것이 아니라면 클라이언트 단에서는 적극적으로 사용해도 큰 문제는 없다.
주의할 점은 클래스의 필드 선언 시에는 사용이 불가능하다는 것이다. 클래스의 링크 코드는 컴파일 시점에 결정되는데
auto
자체는 마치 참조 변수마냥 원래 쓰일 자료형의 별칭이기 때문이다. 참조 변수처럼
auto
혼자서는 존재할 수 없다. 따라서 클래스의 필드 자료형은 모두 명시해야 한다. 또,
auto
의 추론 형식은 가능한 반환하는 값의 원본에 영향을 주지 않도록 추론된다. 함수의 원래 반환형에 참조 한정자가 붙었을 경우
auto
로 반환 값을 받으면 참조 한정자가 무시되고
const
,
volatile
,
*
만 반영된다.






constexpr size_t& GetNumber() noexcept { return myNumber; }constexpr const size_t& GetNumber() const noexcept { return myNumber; }constexpr auto GetNumber2() noexcept { return myNumber; } // 한정자 없는 size_t 반환constexpr auto GetNumber2() const noexcept { return myNumber; } // 한정자 없는 size_t 반환protected:size_t myNumber = 0;}int main(){Counter counter_v{ 300 };constexpr Counter counter_c{ 500 };auto cnt1 = counter_v.GetNumber(); // size_tconst auto cnt2 = counter_v.GetNumber(); // const size_tconst auto& cnt3 = counter_v.GetNumber(); // const size_t& 이지만 실제로는 임시 값이다.size_t cnt4 = counter_v.GetNumber();size_t& cnt5 = counter_v.GetNumber(); // cnt5를 통해 counter_v.myNumber 필드를 수정할 수 있다.const size_t& cnt6 = counter_v.GetNumber(); // counter_v.myNumber 필드의 불변 참조 변수다. auto cnt7 = counter_c.GetNumber(); // size_tauto& cnt8 = counter_c.GetNumber(); // 형식 한정자 오류!const auto& cnt8 = counter_c.GetNumber(); // const size_t& 이며 counter_c.myNumber 필드의 참조 변수다.}
">
이를 극복하기 위해
*
,
&
,
&&
,
const
,
volatile
를 직접 붙일 수 있다. 그러나
auto
를 쓰는 이유가 뭔지 생각해본다면 조금 아쉬운 면이 있다. 실제 코드에서는
const&
또는 때때로 헷갈림 방지를 위해
*
말고는 더 붙일 일이 없을 것이다.


5. using[편집]


키워드
using
을 사용하여 자료형의 별칭(Alias)을 선언할 수 있다. C의
typedef
구문을 대체하는 구문으로써 가독성 상승을 비롯해 템플릿을 사용할 수 있게 되었다.
별칭의 이름으로 주어지는 식별자는 사용자가 구현한 클래스나 템플릿과 마찬가지로 새로운 자료형으로 분류된다. 즉 이 구문은 변수를 선언하는 것처럼 자료형식을 선언하는 것이라고 볼 수 있다. 실제로 표준에서도 자료형을 선언한다고 표현한다. 그러나 참조 변수와 같은 맥락으로 이해해야 한다. 기존의 자료형에 다른 이름을 붙이는 것이기 때문에, 기존의 자료형을 사용하더라도
using
으로 선언한 자료형과 호환된다. 템플릿도 마찬가지라서
void Function(std::vector& vec);
이라는 함수가 있다면, 이 함수에는
using IntVector = std::vector;
와 그냥
std::vector
모두를 인자로 전달할 수 있다.


6. decltype[편집]



6.1. decltype(auto)[편집]


앞서 설명한
auto
는 조금 부족한 면이 있었다.
auto
혼자서는 온전한 자료형을 얻을 수 없기 때문이다. 불필요한 복사가 발생하는 문제도 있다. 해결책으로는
const&
를 붙이는 방법이 있지만 번거롭고 반복적인 작업일 뿐이다. 이에 도입된
decltype(auto)
는 참조형까지 전부 완전한 자료형을 가져온다.
auto
대신에 사용하면 된다.
int main()
{
    Counter counter_v{ 300 };
    constexpr Counter counter_c{ 500 };

    decltype(auto) cnt1 = counter_v.GetNumber(); // size_t& counter_v.myNumber 필드의 참조 변수다. 
    decltype(auto) cnt2 = counter_c.GetNumber(); // const size_t& counter_c.myNumber 필드의 참조 변수다. 

    const decltype(auto)& cnt3 = counter_v.GetNumber(); // 오류! decltype(auto)는 한정자를 붙일 수 없다.
}
참고로 형식 한정자를 붙일 수 없다.


6.2. decltype(expression)[편집]


인자로 전달한 표현식을 묵시적으로 평가한 결과의 자료형을 얻는다. 가령
decltype(50 + 400U)
unsigned int
를 반환한다. 여기서 묵시적으로 평가했다는 말은 표현식이 실제로 실행되지는 않는다는 뜻이다. 오직 반환형만을 알 수 있다. 예를 들어서
decltype((int*)malloc(50000000))
같은 무지막지한 식이라도 얌전히
int*
를 반환할 것이다. 그리고 여기서 알 수 있듯이 표현식이 반드시 상수 표현식일 필요는 없다. 성능 문제가 있을까 싶지만 사용자 단에서 반환형이 무엇인지 알 수 없더라도, C++ 타입 시스템은 반드시 컴파일 시점에 모든 자료형을 확정짓는다.

이것이 유용한 예로는 정수와 큰 정수의 연산, 실수와 정수 사이의 연산, 비용이 큰 연산을 하기 전에 자료형을 가져와서 미리 준비를 할때다. 서로 다른 정수 사이에는 더 바이트 수가 큰 정수로 승급하는 규칙이 있고, 실수와 정수 사이에는 실수로 변환되는 규칙이 있다. 비용이 큰 연산에는 직렬화, 문자열 포맷 등이 있다. 직렬화를 하려면 원본 자료형을 더 작은 자료형으로 변환하거나, 일정한 크기의 메모리에 변환된 값들을 쓰는 과정이 필요하다. 이때 실제로 변환 작업을 하기 전에 먼저 필요한 메모리를 할당하는 수가 있다. 표준 라이브러리에서 사용하는 예로, 시간 라이브러리
에서 서로 다른 시간 단위를 서로 연산할 때, 불필요한 시간 변환 작업을 줄이기 위해
decltype(lhs + rhs)
using
을 사용하여 반환형을 가져온다. 이것 역시
auto
대신에 사용하면 된다.


7. 값 범주 (Value Category)[편집]


C++의 독특한 점이라면 모든 요소를 극한으로 분류했다는 점이다. 값의 종류도 마찬가지다. 이 이란 메모리 상의 어떤 값을 보여주는 요소로써, 식별자(identifier), 예약어(Keyword), 문장부호(Punctuation), 특성(Attribute), 구문(Statement), 템플릿(Template)을 제외한 모든 것이다. 일반적으로 생각되는 변수, 상수로 구별하는 것을 넘어 어디서 어떻게 생겨나고, 어디서 사라지는지, 어떻게 정의되는지, 어떻게 변화되는지, 등 프로그램에서의 메모리 흐름을 완벽히 추종하는 항목이다.

C++ 언어 요소 중에서도 매우 심화되는 내용으로써 이것 역시 필수적으로 알아야하는 내용이 절대 아니다. 이론적으로 매우 심화된 내용이라서 실무 단계에서도 알 필요는 없다. 굳이 알아야 한다면 오히려 메타 프로그래밍보다는 일반화 프로그래밍 단계에서 필요한 내용이다. 일반화 프로그래밍에서 &, const&, &&의 구분, 리터럴 표현, 임시 객체를 이용한 최적화가 필요한 경우 조금 공부해도 손해는 없다.


7.1. lvalue[편집]


Left Referenced Value
  • 이름이 있는 값.
  • const
    가 아니라면 수정할 수 있는 값.
  • 생성자나 함수에 이름을 전달하면 한정자 없는 경우,
    &
    ,
    const&
    순으로 오버로딩을 우선시함
  • 임시 객체의 함수에서 반환된 경우
    &&
    로 취급
  • 이름이 있는 객체의 함수에서 반환된 경우
    &
    또는
    const&
    로 취급

  1. 문자열 리터럴 [const]
  2. 상수 [const]
  3. 람다 표현식이 아닌 함수 [const]
  4. 변수
  5. &
    배열의 인덱스 참조 구문
  6. static_cast
    ,
    static_cast
    와 같이 좌측값 참조 형변환 구문


7.1.1. 문자열 리터럴[편집]


void Function1(const char* string);

void Function2(const char* const& string);

template<size_t Length>
void Function3(const char (&string)[Length]);

void Function4(auto string);

int main()
{
    auto str1 = "wasd"; // 문자열 리터럴은 반드시 const char*
    const auto str2 = "ijkl"; // const char* const
    constexpr auto str3 = "zxcv"; // const char* const&

    Function1("Hello, world! (1)"); // string은 null로 끝나는 문자열
    Function2("Hello, world! (2)"); // string은 null로 끝나는 문자열
    Function3("Hello, world! (3)"); // string은 char의 크기가 18인 문자열
    Function4("Hello, world! (4)"); // string은 null로 끝나는 문자열, const char*

    return 0;
}
C++의 문자열 리터럴은
lvalue
const (&char)[Size]
로 연역된다. 컴파일러에 따라 다르지만, 문자열 리터럴은 실제로 변수에 전달되기 전에는 메모리에 존재하지 않는 값이다. 또는 최적화를 위해 프로그램의 문자열 리터럴을 한데 모은 문자열 풀(Pool)을 구성하고 가져다 쓰기도 한다. C언어 까지는
char[Size]
또는 여기서 연역된
char*
였으나, 이는 실제로 수정할 수 없는 리터럴에 대한 오해를 사게 만들었다. 현재 C++의 문자열 리터럴은 C에서 계승되는 포인터-배열 연역 법칙인
const char*
,
const&
const char*
를 받는
const char* const&
, 그리고
const lvalue
const char[Size]
혹은
const (&char)[Size]
로 나타내진다. 참고로
const char[Size]
는 문자열 배열 안의 값은 복사가 일어나진 않지만, 문자열 배열 식별자의 포인터는 복사가 된다. 사소한 사항이고, 성능에 영향도 거의 없지만, 어쨌든
&
로 받는 걸 추천한다.


7.2. prvalue[편집]


Pure Right Value
  • 이름이 없고 메모리 상에도 존재하지 않는 값
  • & 연산자로 주소를 얻을 수 없는 값
  • 즉시 사용하지 않으면 사라지는 임시 값 [5]
  • 다른 이름이 있는 변수에 할당하기 전까지는 수정할 수 없는 값
  • 선언만 된 미완성 클래스이면 안됨
  • 추상 클래스면 안됨
  • 부모 포인터로 자식 포인터를 받을 수 없음
  • 참조형 또는 포인터가 아니면
    const volatile
    이 될 수 없음 [6]
  • &
    일 수 없음
  • 함수의 인자로 전달하면
    const&
    보다
    &&
    오버로딩을 우선시함
  • 함수의 인자로 전달하면
    &&
    로 취급

  1. 문자열을 제외한 모든 리터럴
  2. 람다 표현식,
    requires
    제약조건식
  3. 반환형이 참조형이 아닌 함수 구문
  4. this
  5. 식별자, 자료형, 열거형, 컨셉트의 이름;
  6. (long)value
    ,
    static_cast
    와 같이 참조가 아닌 형변환 구문


7.3. xvalue[편집]


eXpired Value
  • 이름이 없어 메모리 상에만 존재하는 값
  • & 연산자로 주소를 얻을 수 없는 값
  • 현재 문맥이 끝나면 사라지는 임시 값 [7]
  • const
    가 아니라면 수정할 수 있는 값
  • 선언만 된 미완성 클래스일 수 있음
  • 추상 클래스일 수 있음
  • 부모 포인터로 자식 포인터를 받을 수 있음
  • 함수의 인자로 전달하면
    &
    보다
    &&
    오버로딩을 우선시함.
  • 함수의 인자로 전달하면 클래스는
    &&
    로 취급, 클래스가 아니면
    const&
    로 취급

  1. 클래스 객체의 멤버 참조 구문
    1. class.member
    2. class[index]
  2. 임시 객체의 멤버 참조 구문
    1. int result = A().Get();
  3. &&
    배열의 인덱스 참조 구문
  4. std::move
    ,
    static_cast
    와 같은 우측값 형변환 구문
  5. 문맥을 종료할 수 있는 구문:
    return
    ,
    co_return
    ,
    throw
    [8]


7.4. glvalue (lvalue & xvalue)[편집]


Generalized Left Value


7.5. rvalue (prvalue & xvalue)[편집]


Right Value

[1] bool은 논리 자료형을 의미하는 'Boolean'의 줄임말이다.[2] 그러나 C++14 이하의 버전을 사용해야만 하는데 문자열 처리를 구현해야 하면 공부해서 나쁠 건 없다.[3] 이를 객체(Object)가 아니다라고 한다.[4] 예를 들어 if (handle == NULL) 같은 경우[const] A B C [5] 이 구문이 쓰이지 않으면 최적화될때 사라진다[6] 함수의 반환형이
const int
라면
const
가 항상 무시되고
int
인 것과 같다
[7] 이 구문이 쓰이지 않으면 최적화될때 사라진다[8] Return Value Optimization을 위한 조건이다

파일:CC-white.svg 이 문서의 내용 중 전체 또는 일부는
문서의 r247 판{{{#!wiki style="display: inline; display: 3;"
, 3번 문단}}}에서 가져왔습니다. 이전 역사 보러 가기
파일:CC-white.svg 이 문서의 내용 중 전체 또는 일부는 다른 문서에서 가져왔습니다.
[ 펼치기 · 접기 ]
문서의 r247 판{{{#!wiki style="display: inline; display: 3;"
, 3번 문단}}} (이전 역사)
문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)

문서의 r 판{{{#!wiki style="display: inline; display: none;"
, 번 문단}}} (이전 역사)




파일:크리에이티브 커먼즈 라이선스__CC.png 이 문서의 내용 중 전체 또는 일부는 2023-10-21 19:49:03에 나무위키 C++/문법/자료형 문서에서 가져왔습니다.