데이터 선언을 수정할 때, const 키워드는 개체 또는 변수를 수정할 수 없도록 지정합니다.
구문
1
2
|
const declaration ;
member-function const ;
|
const 값
const 키워드는 변수 값이 상수임을 지정하고 프로그래머가 변수 값을 수정하지 못하도록 컴파일러에 지시합니다.
1
2
3
4
5
6
|
4번줄 5번줄에서 3번줄에서 const로 선언된 i를 수정하려 하니 터지는 다는 것을 보여준다.
C++에서는 상수 값을 정의하기 위해 #define 전 처리기 지시문 대신 const 키워드를 사용할 수 있습니다. const로 정의 된 값은 타입 검사를 받으며 상수 표현식 대신 사용할 수 있습니다.
C++에서 다음과 같이 const 변수를 사용하여 배열의 크기를 지정할 수 있습니다.
1
2
3
4
|
// compile with: /c
const int maxarray = 255;
char store_char[maxarray]; // allowed in C++; not allowed in C
|
4번줄 주석을 보면, C++ 에선 되는데 C에선 안된다는 말을 한다....???
실험결과 아예 빨간줄을 긋는 것으로 나타난다.
C에서 상수 값은 기본적으로 외부 연결이므로 소스 파일에만 나타날 수 있습니다. C++에서 상수 값은 내부 링크로 기본 설정되어 있으므로 헤더 파일에 나타날 수 있습니다.
const 키워드는 포인터 선언에서도 사용할 수 있습니다.
1
2
3
4
5
6
7
|
int main() {
char *mybuf = 0, *yourbuf;
char *const aptr = mybuf;
*aptr = 'a'; // OK
aptr = yourbuf; // C3892
}
|
3번줄은 그냥 char 포인터이며, 4번줄이 char형의 const 포인터이다.
4번줄의 포인터는 상수값으로 취급되어 변경될 수 없다.
const로 선언된 변수에 대한 포인터는 const로 선언된 포인터에만 할당할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
|
#include <stdio.h>
int main() {
const char *mybuf = "test";
char *yourbuf = "test2";
printf_s("%s\n", mybuf);
const char *bptr = mybuf; // Pointer to constant data
printf_s("%s\n", bptr);
// *bptr = 'a'; // Error
}
|
4번줄에 정의된 const char 형의 포인터를 8번줄의 같은 형으로 받는 모습을 보여준다.
바로 위 예제와 다른점은 const char의 포인터형과 char const 포인터는 엄연히 다르며, 전자는 const화 된 char를 뜻하고 후자는 const화 된 char의 포인터를 뜻한다. 즉, const char 포인터는 수정이 가능하지만 char const는 상수화 된 값이라 수정이 불가능하다.
상수 데이터에 대한 포인터를 함수 매개 변수로 사용하여 함수가 포인터를 통해 전달 된 매개 변수를 수정하지 못하도록 할 수 있습니다.
const로 선언 된 객체의 경우 상수 멤버 함수 만 호출 할 수 있습니다. 이렇게하면 상수 개체가 수정되지 않습니다.
1
2
|
birthday.getMonth(); // Okay
birthday.setMonth( 4 ); // Error
|
const화 되지 않은 객체에 대해 상수 또는 비 상수 멤버 함수를 호출할 수 있습니다. const 키워드를 사용하여 멤버 함수를 오버로드 할 수도 있습니다.-이렇게 하면 const화 된 객체 및 const화 되지 않은 객체에 대해 다른 버전의 함수를 호출 할 수 있습니다.
자체예제_
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
class A
{
public:
void func1()
{
cout << "A class func1" << endl;
}
void func1() const
{
cout << "A class const func1" << endl;
}
public:
A() {}
~A() {}
};
int main()
{
A a;
a.func1();
const A ac = A();
ac.func1();
}
|
자체예제 실행결과_
1
2
|
A class func1
A class const func1
|
자체 예제 결과 해당 설명은...
- 같은 이름으로 선언된 두 함수 중 하나에 const 지정자가 쓰인 경우를 만든다. (클래스 멤버함수 참고)
- const로 선언된 객체에선 const 지정자가 쓰인 함수를 호출한다. -> 9번줄 void func1() const 호출
- 그렇지 않은 객체에선 const 지정자가 쓰이지 않은 함수를 호출한다. -> 4번줄 void func1() 호출
const 키워드로 생성자 또는 소멸자를 선언할 수 없습니다.
const 멤버 함수
const 키워드로 멤버 함수를 선언하면 함수가 호출된 객체를 수정하지 않는 "읽기 전용(read-only)" 함수임을 지정합니다. 상수 멤버 함수는 비정적(non-static) 데이터 멤버를 수정하거나 상수가 아닌 멤버 함수를 호출 할 수 없습니다.
상수 멤버 함수를 선언하려면 인수 목록의 닫는 괄호 뒤에 const 키워드를 추가하십시오. const 키워드는 선언과 정의 모두에 필요합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
class Date
{
public:
Date( int mn, int dy, int yr );
int getMonth() const; // A read-only function
void setMonth( int mn ); // A write function; can't be const
private:
int month;
};
int Date::getMonth() const
{
return month; // Doesn't modify anything
}
void Date::setMonth( int mn )
{
month = mn; // Modifies data member
}
int main()
{
Date MyDate( 7, 4, 1998 );
const Date BirthDate( 1, 18, 1953 );
MyDate.setMonth( 4 ); // Okay
BirthDate.getMonth(); // Okay
BirthDate.setMonth( 4 ); // C2662 Error
}
|
C 와 C++ 에서 const 차이점
변수를 C 소스 코드 파일에서 const로 선언하면 다음과 같이됩니다.
1
|
const int i = 2;
|
그런 다음, 이 변수를 다음과 같이 다른 모듈에서 사용할 수 있습니다.
1
|
extern const int i;
|
그러나 C++에서 동일한 동작을 얻으려면, const 변수를 다음과 같이 선언해야합니다.
1
|
extern const int i = 2;
|
C 소스 코드 파일에서 extern 변수를 선언하여 C 소스 코드 파일에서 사용하려면 다음을 사용하
십시오.
1
|
extern "C" const int x=10;
|
C++ 컴파일러에 의한 네임 맹글링(name mangling)을 방지합니다.
*
name mangling_
자자.... 이거 함수와 관련된 Post가 필요한데 아직 작성하지 못했다...;ㅠㅠ
차후에 연결지을 포스팅이 완성될 것이다!!!!!
점점 MSDN 볼 항목이 많아지니 좀만내려가면 된다ㅇㅇㅇ!!!!!!!!!!!!!!!!!
참고
멤버 함수의 매개 변수 목록을 따를 때 const 키워드는 함수가 호출된 객체를 수정하지 않도록 지정합니다.
const에 대한 자세한 내용은 다음 항목을 참조하십시오.
constexpr (C++)
constexpr 키워드는 C ++ 11에 도입되었으며 C ++ 14에서 개선되었습니다. 상수 표현(constant expression)을 의미합니다.
const와 같은 점은 변수에 적용하여 코드가 값을 수정하려고하면 컴파일러 오류가 발생합니다.
const와 다른 점은 constexpr은 함수와 클래스 생성자에도 적용될 수 있습니다. constexpr은 값 또는 반환 값이 상수임을 나타냅니다. 가능한 경우 컴파일 타임에 계산됩니다. -> 성능(런타임) 향상, 컴파일 시 고생!! 이란 말이다.
constexpr 정수 값은 템플릿 인수 및 배열 선언과 같이 const 정수가 필요한 모든 위치에서 사용할 수 있습니다. 그리고 런타임이 아닌 컴파일 타임에 값을 계산할 수 있다면 프로그램 실행 속도를 높이고 메모리 사용량을 줄일 수 있습니다.
컴파일 타임 상수 계산의 복잡성과 컴파일 타임에 미칠 수 있는 영향을 제한하기 위해 C++ 14 표준은 상수 표현식의 유형을 리터럴 유형(literal types)으로 요구합니다.
구문
constexpr literal-type identifier = constant-expression ;
constexpr literal-type identifier {constant-expression } ;
constexpr literal-type identifier ( params ) ;
constexpr ctor ( params );
Parameters
params
하나 이상의 매개 변수에서 각 매개 변수는 리터럴 유형이어야하며 그 자체가 상수 표현이어야합니다.
반환 값
constexpr 변수와 함수는 반드시 literal type 을 반환합니다.
literal_type_**
리터럴 유형은 컴파일 타임에 레이아웃을 결정할 수있는 유형입니다. 다음은 리터럴 유형입니다.
- void
- scalar 형
- references 참조 형
- void, scalar, 참조 형의 배열
- trivial 소멸자가 있는 클래스와 생성자를 이동하거나 복사하지 않는 하나 이상의 constexpr 생성자를 가진 클래스. 또한 모든 비정적 데이터 멤버 및 기본 클래스는 리터럴 형식이어야하며 volatile이 아니어야합니다.
쉽게 말하면, 컴파일 시간에 처리되는 constexpr의 특성에 맞추어 컴파일 시간에 처리될 수 있어야 함을 의미한다.
후에 해당 키워드를 설명하는 포스트가 있을 시 링크를 걸겠다.
출처: https://mtding.tistory.com/18 [M_TDING]
constexpr 변수
const 변수와 constexpr 변수의 주요 차이점은 런타임까지 const 변수의 초기화를 연기할 수 있다는 것입니다. 컴파일 타임에 constexpr 변수를 반드시 초기화 합니다. 모든 constexpr 변수는 const입니다.
- 변수가 리터럴 타입이고 초기화 된 경우 constexpr을 사용하여 변수를 선언할 수 있습니다. 초기화가 생성자에 의해 수행되면 생성자는 constexpr로 선언되어야합니다.
- 참조하는 객체가 상수 표현식에 의해 초기화되고 초기화 중에 호출되는 암시적 변환이 상수 표현식이라면 참조는 constexpr로 선언될 수 있습니다.
- constexpr 변수 또는 함수의 모든 선언에는 constexpr 지정자가 있어야 합니다.
3번 항목은 constexpr 을 표기해야 한다는 비교적 당연한 이야기이다. 하지만 1번 항목과 2번 항목에 대한 예제는 존재하지 않아 변수 선언에 대해 나름 예제를 만들어 보았다.
2번 항목 예제_
1
2
|
constexpr float j = 0;
constexpr int k = j + 1;
|
float 가 int 로 암시적 형변환이 이루어질 수 있느냐는 것이다. 해당 코드는 컴파일은 문제 없이 잘 되었다.
!아직 제대로된 예제가 아니니 주의바람! - 쏠까 당최 뭔 코든지 생각이 나질 않는다.
1번 항목 예제_
1
2
3
4
5
6
7
8
9
10
11
|
class XX
{
public:
constexpr XX() : x(0) {};
};
int main()
{
constexpr XX tx = XX();
}
|
위 코드는 정상적으로 진행된다. 만약 4번줄, 생성자에서 constexpr 지정자가 빠질 경우 다음과 같은 오류가 생긴다.
1
2
3
4
5
6
7
8
9
10
11
|
class XX
{
public:
XX() : x(0) {};
};
int main()
{
constexpr XX tx = XX();
}
|
1
2
3
4
5
6
|
constexpr float x = 42.0;
constexpr float y{108};
constexpr float z = exp(5, 3);
constexpr int i; // Error! Not initialized
int j = 0;
constexpr int k = j + 1; //Error! j not a constant expression
|
3번줄 에 exp(5, 3) 함수가 리터럴 타입을 반환할 뿐만 아니라 constexpr로 지정되어있어야 한다.
함수에 대한 constexpr 형은 아래에 나온다.
constexpr 함수
constexpr 함수는 반환 값을 [소비 코드를 요구할 때](consuming code requires) 컴파일 시간에 계산할 수 있는 함수입니다. 예를 들면, 소비코드는 constexpr 변수를 초기화 하거나 비형식(non-type) 템플릿 매개변수를 제공할 때 컴파일 시간에 반환 값을 요구합니다. 매개변수가 constexpr 값인 경우 constexpr 함수는 컴파일 시간 상수를 생성합니다. constexpr 인자가 아닌 값(non-constexpr)으로 호출하거나 컴파일 타임에 해당 값이 필요하지 않은 경우 일반 함수처럼 런타임에 값을 생성합니다. (이 이중 동작은 동일한 함수의 constexpr 및 non-constexpr 버전을 작성하지 않아도 됩니다.)
constexpr 함수 또는 생성자는 암시적으로 인라인입니다.
constexpr 함수에는 다음 규칙이 적용됩니다.
- constexpr 함수는 반드시 리터럴 형식(literal_types)만을 받고 반환해야 합니다.
- constexpr 함수는 재귀함수일 수 있습니다.
- 그것은 가상함수일 수 없습니다. 둘러싸는 클래스에 어떠한 가상 기본 클래스가 있는 경우, 생성자를 constexpr로 정의할 수 없습니다. - 컴파일 시간에 결정할 수 가 없다는 뜻
- 함수의 구현부는 = default (기본값) 또는 = delete (비정의)로 정의할 수 있습니다.
- 함수의 구현부에는 goto 문이나 try 블록이 포함될 수 없습니다.
- constexpr가 아닌 템플릿의 명시적인 특수화는 constexpr로 선언될 수 있습니다.
- constexpr 템플릿의 명시적 특수화는 constexpr 일 필요는 없습니다.
다음 규칙은 Visual Studio 2017 이상에서 constexpr 함수에 적용됩니다.
- if 및 switch 문과 for, range-based for, while 및 do-while을 비롯한 모든 반복문을 포함할 수 있습니다.
- 로컬 변수 선언을 포함 할 수 있지만 변수는 초기화 되어야하고 리터럴 유형이어야 하며, static 또는 thread-local 일 수 없습니다. 국지적으로 선언 된 변수는 const 일 필요는 없으며 변경될 수 있습니다.
- constexpr 으로된 비정적(non-static) 멤버 함수는 암시적으로 const일 필요는 없습니다.
공식사이트에 올라와 있는 예제다.
1
2
3
4
5
6
|
constexpr float exp(float x, int n)
{
return n == 0 ? 1 :
n % 2 == 0 ? exp(x * x, n / 2) :
exp(x * x, (n - 1) / 2) * x;
};
|
해당 예제는 제귀함수를 이용한 모습을 보여준다.
필자는 constexpr 지정자를 사용해 함수를 꾸릴 경우 하면 안되거나, 주의사항 몇 가지를 직접 실험해보았다. 물론 오류가 떠서 컴파일을 못했지만 어떤 오류가 뜨는지 확실히 해야할 필요가 있다고 생각했다.
본문 3번 - 함수가 virtual인 경우
터짐1
본문 5번 - 구현부에서 try나 goto를 쓸 경우
본문 1번 - 함수에서 사용하는 변수나 인자가 literal_type이 아니고 constexpr이 아닌 경우
본문 2017이하 2번 - 함수 구현부에서 static, thread_local을 사용한 경우
팁_
Visual Studio 디버거에서 최적화되지 않은 디버그 빌드를 디버깅 할 때 컴파일 타임에 중단점을 넣어 constexpr 함수가 평가되는지 여부를 알 수 있습니다. 중단점에 도달하면 함수가 런타임에 호출됩니다. 그렇지 않으면 컴파일 타임에 함수가 호출됩니다.
extern constexpr
/Zc:externConstexpr 컴파일러 옵션을 사용하면 컴파일러에서 extern constexpr을 사용하여 선언된 변수에 외부 연결을 적용합니다. 이전 버전의 Visual Studio에서는 기본값 또는 /Zc:externConstexpr-이 지정된 경우 Visual Studio는 extern 키워드가 사용되는 경우에도 constexpr 변수에 내부 연결을 적용합니다. /Zc:externConstexpr 옵션은 Visual Studio 2017 Update 15.6부터 사용할 수 있습니다. 기본적으로 꺼져 있습니다. /permissive- 옵션은 /Zc:externConstexpr을 활성화하지 않습니다.
예제
다음 예제는 constexpr 변수, 함수 및 사용자 정의 유형을 보여줍니다. main()의 마지막 문에서, constexpr 멤버 함수 GetValue()는 컴파일 시간에 값을 요구하지 않으므로 런타임 호출입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
#include <iostream>
using namespace std;
// Pass by value
constexpr float exp(float x, int n)
{
return n == 0 ? 1 :
n % 2 == 0 ? exp(x * x, n / 2) :
exp(x * x, (n - 1) / 2) * x;
};
// Pass by reference
constexpr float exp2(const float& x, const int& n)
{
return n == 0 ? 1 :
n % 2 == 0 ? exp2(x * x, n / 2) :
exp2(x * x, (n - 1) / 2) * x;
};
// Compile-time computation of array length
template<typename T, int N>
constexpr int length(const T(&ary)[N])
{
return N;
}
// Recursive constexpr function
constexpr int fac(int n)
{
return n == 1 ? 1 : n*fac(n - 1);
}
// User-defined type
class Foo
{
public:
constexpr explicit Foo(int i) : _i(i) {}
constexpr int GetValue()
{
return _i;
}
private:
int _i;
};
int main()
{
// foo is const:
constexpr Foo foo(5);
// foo = Foo(6); //Error!
// Compile time:
constexpr float x = exp(5, 3);
constexpr float y { exp(2, 5) };
constexpr int val = foo.GetValue();
constexpr int f5 = fac(5);
const int nums[] { 1, 2, 3, 4 };
const int nums2[length(nums) * 2] { 1, 2, 3, 4, 5, 6, 7, 8 };
// Run time:
cout << "The value of foo is " << foo.GetValue() << endl;
}
|
62번줄 에서는 GetValue() constexpr 꼴로 받지 않는다. 따라서, 이 이유로 인해 런타임 실행이라 설명한다.
요구사항
Visual Studio 2015
참고
Declarations and Definitions
const
좋아요 공감
공유하기
글 요소
'C++' 카테고리의 다른 글
저장소 클래스 - Storage classes (static, extern, thread_local, register) (0) | 2019.12.25 |
---|---|
Timer - 시간 측정기 (0) | 2019.12.25 |
Scope - 범위 (0) | 2019.12.25 |
선언지정자 - 정의 및 개요 (헷갈리는 선언 포함) (0) | 2019.12.25 |
연산자 static_cast + const_cast + reinterpret_cast (0) | 2019.12.25 |