정적 상수 문자열(클래스 멤버)
클래스(이 경우 쉐이프 팩토리)에 대해 전용 정적 상수를 설정하려고 합니다.
그런 종류의 것을 먹고 싶어요.
class A {
private:
static const string RECTANGLE = "rectangle";
}
유감스럽게도 C++(g++) 컴파일러에서 다음과 같은 모든 종류의 오류가 발생합니다.
ISO C++는 'RECTANGLE' 멤버의 초기화를 금지합니다.
비표준 유형 'std::string'의 정적 데이터 멤버에 대한 클래스 내 초기화가 잘못되었습니다.
오류: 'RECTANGLE'을 정적으로 설정
이런 종류의 부재 디자인은 규격에 맞지 않는다는 것을 알 수 있습니다.#define 디렉티브를 사용하지 않고 프라이빗 리터럴 상수(또는 퍼블릭)를 갖는 방법(데이터 전역성의 추악함을 피하고 싶다!)
어떤 도움이라도 감사합니다.
클래스 정의 외부에 스태틱멤버를 정의하고 이니셜라이저를 지정해야 합니다.
첫번째
// In a header file (if it is in a header file in your case)
class A {
private:
static const string RECTANGLE;
};
그리고 나서.
// In one of the implementation files
const string A::RECTANGLE = "rectangle";
원래 사용하려고 했던 구문(클래스 정의 내 이니셜라이저)은 정수 및 열거형에서만 사용할 수 있습니다.
C++17부터는 인라인 변수와 같은 다른 옵션이 있습니다.
// In a header file (if it is in a header file in your case)
class A {
private:
inline static const string RECTANGLE = "rectangle";
};
추가 정의는 필요하지 않습니다.
C++11에서는 다음 작업을 수행할 수 있습니다.
class A {
private:
static constexpr const char* STRING = "some useful string constant";
};
내부 클래스 정의에서는 정적 멤버만 선언할 수 있습니다.클래스 밖에서 정의해야 합니다.컴파일 시간 적분 상수의 경우 표준에서는 멤버를 "초기화"할 수 있는 예외를 만듭니다.하지만 아직 정의는 아닙니다.예를 들어, 주소를 받는 것은 정의가 없으면 작동하지 않습니다.
상수에 std::string over const char[]를 사용하는 이점은 없습니다.std::string은 매우 편리하며 동적 초기화가 필요합니다.그래서 이렇게 쓰면
const std::string foo = "hello";
네임스페이스 범위에서 foo의 컨스트럭터는 메인 시작 직전에 실행되며 이 컨스트럭터는 히프 메모리에 상수 "hello"의 복사본을 만듭니다.RECTURE를 std:: 문자열로 사용할 필요가 없는 한, 다음과 같이 쓸 수 있습니다.
// class definition with incomplete static member could be in a header file
class A {
static const char RECTANGLE[];
};
// this needs to be placed in a single translation unit only
const char A::RECTANGLE[] = "rectangle";
여기! 힙 할당도 복사도 동적 초기화도 없습니다.
건배!
C++17에서는 인라인 변수를 사용할 수 있습니다.
class A {
private:
static inline const std::string my_string = "some useful string constant";
};
이것은 심연과는 다르다는 것에 주의해 주세요.7의 답변:이것은 실제를 정의한다.std::string
오브젝트, a가 아닌const char*
이는 추가 정보일 뿐이지만 헤더 파일에 문자열을 삽입하려면 다음과 같이 하십시오.
class foo
{
public:
static const std::string& RECTANGLE(void)
{
static const std::string str = "rectangle";
return str;
}
};
추천은 안 되겠지만요
클래스 스태틱 변수는 헤더로 선언할 수 있지만 .cpp 파일로 정의해야 합니다.이는 정적 변수의 인스턴스는 하나만 있을 수 있고 컴파일러는 생성된 객체 파일을 어떤 파일에 넣을지 결정할 수 없기 때문에 사용자가 결정을 내려야 하기 때문입니다.
C++11 선언을 사용하여 정적 값의 정의를 유지하기 위해 중첩된 정적 구조를 사용할 수 있습니다.이 경우 스태틱멤버는 구조체이며 .cpp 파일로 정의해야 하는데 값은 헤더에 있습니다.
class A
{
private:
static struct _Shapes {
const std::string RECTANGLE {"rectangle"};
const std::string CIRCLE {"circle"};
} shape;
};
.cpp에서는 스태틱 구조 전체가 개별 멤버를 초기화하지 않고 초기화됩니다.
A::_Shapes A::shape;
값에 액세스하려면
A::shape.RECTANGLE;
또는 --멤버는 비공개이며 A에서만 사용하도록 되어 있기 때문에 --와
shape.RECTANGLE;
이 솔루션에서는 여전히 정적 변수의 초기화 순서에 문제가 있습니다.정적 값을 사용하여 다른 정적 변수를 초기화할 경우 첫 번째 변수가 아직 초기화되지 않을 수 있습니다.
// file.h
class File {
public:
static struct _Extensions {
const std::string h{ ".h" };
const std::string hpp{ ".hpp" };
const std::string c{ ".c" };
const std::string cpp{ ".cpp" };
} extension;
};
// file.cpp
File::_Extensions File::extension;
// module.cpp
static std::set<std::string> headers{ File::extension.h, File::extension.hpp };
이 경우 정적 변수 헤더에는 링커에 의해 작성된 초기화 순서에 따라 {"} 또는 {.h", ".hpp"}이 포함됩니다.
@abys.7에서 언급했듯이constexpr
컴파일 시 변수 값을 계산할 수 있는지 여부를 지정합니다.하지만 만약 당신이 당신의 끈을 선언한다면static constexpr const char*
프로그램에서는std::string
그렇지 않으면, 새로운 것이 있기 때문에 오버헤드가 생길 것이다.std::string
다음과 같은 상수를 사용할 때마다 객체가 생성됩니다.
class A {
public:
static constexpr const char* STRING = "some value";
};
void foo(const std::string& bar);
int main() {
foo(A::STRING); // a new std::string is constructed and destroyed.
}
클래스 내 초기화 구문을 사용하려면 상수 표현에 의해 초기화되는 정수 또는 열거 유형의 정적 상수여야 합니다.
이것이 제한 사항입니다.따라서 이 경우 클래스 외부에 변수를 정의해야 합니다.@Andrey에서 회답하다t
가능한 경우 다음 작업을 수행합니다.
static const std::string RECTANGLE() const {
return "rectangle";
}
또는
#define RECTANGLE "rectangle"
그 중 하나를 선택하셔도 됩니다.const char*
위에서 설명한 솔루션이지만 스트링이 항상 필요한 경우 많은 오버헤드가 발생합니다.
한편 스태틱 문자열은 동적 초기화가 필요하므로 다른 글로벌/스태틱 변수 초기화 중에 해당 값을 사용하려는 경우 초기화 순서 문제가 발생할 수 있습니다.이를 피하기 위해 가장 저렴한 방법은 getter를 통해 정적 문자열 개체에 액세스하는 것입니다. getter는 객체가 초기화되었는지 여부를 확인합니다.
//in a header
class A{
static string s;
public:
static string getS();
};
//in implementation
string A::s;
namespace{
bool init_A_s(){
A::s = string("foo");
return true;
}
bool A_s_initialized = init_A_s();
}
string A::getS(){
if (!A_s_initialized)
A_s_initialized = init_A_s();
return s;
}
말고 꼭 '''만 사용하세요.A::getS()
스레드화는 다음 방법으로만 시작할 수 있습니다.main()
, , , , 입니다.A_s_initialized
되어 있습니다.main()
멀티 스레드 환경에서도 잠금이 필요 없습니다. A_s_initialized
전), 「0」을 사용하고 있는 는, 「0」이 됩니다.getS()
가 초기화되기 전에 init 함수를 안전하게 호출합니다.
Btw, 위의 답변 "static const std::string RECTURE() const"에서 정적 함수는 사용할 수 없습니다.const
오브젝트가 있는 경우 상태를 변경할 수 없기 때문입니다(이 포인터는 없습니다).
현재 표준에서는 정적 상수 적분 유형에 대해서만 이러한 초기화가 허용됩니다.그러니 안드레이트의 설명대로 해야 해단, 새로운 멤버 초기화 구문을 통해 다음 표준에서 사용할 수 있습니다.
2018년과 C++17로 빠르게 이동합니다.
- std:: string을 사용하지 않고 std:: string_view 리터럴을 사용합니다.
- 아래 'constexpr'에 주목해 주세요.이것은 「컴파일 시간」메커니즘이기도 합니다.
- no inline은 반복을 의미하지 않습니다.
- 여기에는 cpp 파일이 필요하지 않습니다.
static_module은 컴파일 시에만 '작동'합니다.
using namespace std::literals; namespace STANDARD { constexpr inline auto compiletime_static_string_view_constant() { // make and return string view literal // will stay the same for the whole application lifetime // will exhibit standard and expected interface // will be usable at both // runtime and compile time // by value semantics implemented for you auto when_needed_ = "compile time"sv; return when_needed_ ; }
};
위는 적절한 법적 기준 C++ 시민입니다.모든 표준: 알고리즘, 컨테이너, 유틸리티 등에 쉽게 관여할 수 있습니다.예를 들어 다음과 같습니다.
// test the resilience
auto return_by_val = []() {
auto return_by_val = []() {
auto return_by_val = []() {
auto return_by_val = []() {
return STANDARD::compiletime_static_string_view_constant();
};
return return_by_val();
};
return return_by_val();
};
return return_by_val();
};
// actually a run time
_ASSERTE(return_by_val() == "compile time");
// compile time
static_assert(
STANDARD::compiletime_static_string_view_constant()
== "compile time"
);
표준 C++를 즐겨보세요.
언급URL : https://stackoverflow.com/questions/1563897/static-constant-string-class-member
'programing' 카테고리의 다른 글
OleDB 및 Excel 혼합 데이터 유형: 데이터 누락 (0) | 2023.04.22 |
---|---|
Xcode 6 버그: Interface Builder 파일의 알 수 없는 클래스 (0) | 2023.04.22 |
sql 기본 키 및 인덱스 (0) | 2023.04.17 |
c# 코드로 Data Template를 빌드하려면 어떻게 해야 하나요? (0) | 2023.04.17 |
Swift 어레이 할당에 일관성이 없는 이유(레퍼런스나 딥 카피 모두)가 있습니까? (0) | 2023.04.17 |