programing

정적 상수 문자열(클래스 멤버)

lastcode 2023. 4. 22. 09:31
반응형

정적 상수 문자열(클래스 멤버)

클래스(이 경우 쉐이프 팩토리)에 대해 전용 정적 상수를 설정하려고 합니다.

그런 종류의 것을 먹고 싶어요.

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

반응형