C++ 에서의 class Variable 동적할당

조회수 1871회

Python의 class variable처럼 C++에서 class variable을 사용하는데 이를 동적할당으로 사용하고 싶습니다.

#include <iostream>
class Some{
    private:
        static Some* _A;
    public:
        void __setSome(int n){
            this -> _A = new Some[n];
        }
};

int main(){
    Some A;
    A.__setSome(5);
}

다음과 같이 코드를 짜면 컴파일에러가 발생합니다. 무엇이 잘못된 것인가요?

2 답변

  • 시작하기 전에 C++ 에는 class variable 이란 명칭은 없고 static member variable 이란 명칭이 있습니다.

    제 생각에는 컴파일 오류가 아니라 링크 오류가 발생할 것이라 생각합니다.

    정적 멤버 변수는 클래스 외부에서 한번 정의를 해주어야합니다.

    class Some{
        private:
            static Some* _A;
        public:
            void __setSome(int n){
                this -> _A = new Some[n];
            }
    };
    Some* Some::_A;
    

    스마트 포인터를 사용하는 것이 조금더 안전하고 의도에 적합 할 것 입니다.

    #include <iostream>
    #include <memory>
    
    class Some{
        private:
            static std::unique_ptr<Some[]> _A;
        public:
            void __setSome(int n){
                _A.reset(new Some[n]);
            }
    };
    
    std::unique_ptr<Some[]> Some::_A;
    
    int main(){
        Some A;
        A.__setSome(5);
    }
    

    이런 방법을 이용하면 프로그램이 종료 될때 알아서 메모리를 해제하게 됩니다.

    만약 C++11 을 이용할 수 없을 때는 아래와 같은 방법도 있습니다.

    #include <iostream>
    
    class Some{
        struct Ptr {
            Some* ptr;
            Ptr() : ptr() {}
            ~Ptr() { delete[] ptr; }
            void reset(Some* p) {
                delete[] ptr;
                ptr = p;
            }
            Some& operator[](std::size_t i) { return ptr[i]; }
            Some* operator->() { return ptr; }
            Some& operator*() { return *ptr; }
        };
        private:
            static Ptr _A;
        public:
            void __setSome(int n){
                _A.reset(new Some[n]);
            }
    };
    
    Some::Ptr Some::_A;
    
    int main(){
        Some A;
        A.__setSome(5);
    }
    
    • 친절한 답변 감사합니다!. 그리고 추가적인 의문사항이지만, 어째서 바깥에서 초기화를 해줘야 하는건가요? 클래스 내부 자체에서 초기화문을 넣어줄 수 없는건가요? 해당 소스코드가 다른 파일에 분리되어있고, import 해야하는 과정에서 문제가 발생할 수도 있잖아요. dbwodlf3 2017.10.16 18:48
    • 정적 멤버 변수는 전역 변수와 비슷하다고 생각하시면 됩니다. 전역 변수도 헤더 파일에 `extern int a;` 와 같은 식으로 선언 해두고, 실제 변수는 cpp 파일에 `int a;` 와 같이 정의하여 여러 소스코드에서 사용할 수 있듯이, 정적 멤버 변수도 cpp 파일에서 정의가 필요 합니다. class 에 있는건 선언 정도로 생각하시면 됩니다. 유동욱 2017.10.16 21:47
  • c++을 파이썬 네이밍룰을 적용했군요...

    c++ 과 파이썬은 차원이 다른 언어입니다.

    일단 컴파일 오류는 static Some* _A; 에서 날겁니다. static 은 클래스 변수를 가리킵니다. 또한 초기화가 빠져있기 때문에 쓰레기 값(주소)을 가르키고 있을 겁니다.

    Some* _A = NULL;
    

    와 같이 명시적으로 초기화를 해줍니다.

    static 제거와 초기화를 하면 컴파일 오류는 없을 겁니다.

    그런데 위의 예제는 메모리 누수(leak)가 생길 수 있습니다.

    void __setSome(int n){
        this -> _A = new Some[n];
    }
    

    __setSome 메소드에서 n개의 Some 객체를 힙에다 생성합니다. 해제(제거)는 어디서 해야 할까요?

    c++에서 이런식의 코드는 상당히 위험합니다.

    최소한 소멸자를 이용해서 명시적으로 제거를 하던지 스마트 포인터를 활용해서 처리해야 합니다.

    ~Some(){
       // if(_A != NULL) delete[] _A;
       if(!_A) delete[] _A;  // 이것이 더 적합한 방법이겠네요.
    }
    
    • 프로그래밍을 하면서 대부분의 프로그래머들이 말하기를, 생성을 했으면 해제를 해야한다고 하더군요. 쓸모가 없어지면 그냥 해당 객체를 그냥 삭제하면 되지 않나요? 해당 객체의 해당 부분만 삭제할게 아니라. 아니면, 어떠한 메모리를 free하게 해준다는게, 데이터는 그대로 남아있고 그냥 더 이상의 메모리를 확보하지 않는다는 명시적인 선언인가요? 아니면 해당 객체가 삭제될 때에, 동적으로 할당된 메모리에대한 정보가 없으므로 소멸자 자체에 명시적으로 제거해야한다는 의미이군요. 아하. 감사합니다. 근시안적인 눈이라서 그런지 다 이해도 안하고 댓글을 다네여 ㅇㅁㄴㅁㅇㅁㄴㅇ dbwodlf3 2017.10.16 18:41

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)