2013-12-17 3 views
3

나는 다음과 같은 구조체가 있습니다 이연 멤버 건설

struct Logger::LoggerImpl { 
    std::wofstream loggerStream; 
} 

내가 분명히 표준 : wofstream이 (컴파일러의 기본 생성자를 통해) 내재적으로 작성됩니다 LoggerImpl을 만들

.

내 질문은 wofstream의 건설을 방지 (또는 연기) 할 수있는 방법은 포인터를 사용하지 않고,있다,있다? 왜냐하면 나중에 주어진 파일 이름으로 생성 할 것이기 때문입니다.

나는이 경우는 약간의 차이가 있음을 알지만, 이론적으로 부탁 해요. 당신의 정의를 늘릴 경우

+0

"포인터를 사용하지 않고"- 그 이유는 무엇입니까? 포인터는 확실한 해결책처럼 보입니다. 그냥 거기에 그것을 초기화하는 동안 분명히 할당 할 것입니다, 그리고 당신은 분명히 어떤 단계에서도 null이 될 수없는 참조가 있다면. –

+0

포인터가 아니라면 부모가 생성되는 것과 동시에 생성됩니다. 그것에 대해 할 수있는 일이별로 없습니다. 유일한 다른 선택은 두 부분으로 구성된 구조이지만'logger' 클래스가 아닌'wofstream' 클래스를위한 것입니다. –

+0

왜 포인터없이 이것을하고 싶습니까? 이유가 있니? – Netherwire

답변

4

당신은, "포인터를 사용하지 않고" "직접 std::wofstream *를 사용하지 않고"을 의미 할 수 있습니다 직접 std::wofstream *을 처리하지 않는 때문에

struct Logger::LoggerImpl { 
    std::shared_ptr<std::wofstream> loggerStream; 


    void init() { 
     loggerStream = std::make_shared<std::wofstream>(); 
    } 
}; 

내가 뻗어 말. 그게 내가 생각할 수있는 최선이야.

+3

포인터입니다. –

+0

_ [좋아, 이미 인정했다. 아직도, 나는 그것이 단 한마디의 말로 말하면서, curtly하는 것이 필요하다고 느꼈다. : P 길고 짧게는 질문에 대답하지 않았다는 것이지만, 적어도 그가 여전히 그의 편에 RAII를 가지고 있기 때문에 이것은 OP에 대한 올바른 접근법이라고 생각합니다. +1] _ –

+0

글쎄, 만약 당신이 그것에 대해 생각한다면, 포인터를 사용하지 않고 STL을 사용할 수 없다. 포인터가 내부적으로 모두 사용되기 때문이다. 스택에'std :: wofstream'을 선언하더라도 여전히 포인터를 사용하고있는 것입니다, 맞습니까? 저도 같은 생각입니다. 'std :: shared_ptr'는 포인터를 직접 사용하며 간접적으로 사용합니다. – Anthony

1

다양한 상황에서 회원 구성을 연기하는 것은 많은 의미가 있습니다. 여기에 몇 가지 방법이 있습니다. 구현 간의 차이점은 연기의 목적이 다르기 때문입니다.

최초 사용시 초기화; 이유 : 필요할 때까지 자원을 낭비하지 않아야합니다.

class Logger::LoggerImpl 
{ 
private: 
    std::wofstream * loggerStream; // Don't expose to other classes 

    std::wofstream * GetLoggerStreamImpl() 
    { 
     if(loggerStream == NULL) 
     { 
      loggerStream = new std::wofstream; 
     } 

     return loggerStream; 
    } 

public: 
    LoggerImpl() : loggerStream(NULL) 
    { 
    } 

    std::wofstream * GetLoggerStream() 
    { 
     return GetLoggerStreamImpl(); 
    } 

    void DoSomethingWithLoggerStream() 
    { 
     GetLoggerStreamImpl(); 
     // Do whatever you need with loggerStream 
    } 
}; 

전용 방법으로 초기화; 이유 : 이전에 초기화 매개 변수를 알 수 없었습니다.

class Logger::LoggerImpl 
{ 
private: 
    std::wofstream * loggerStream; // Don't expose to other classes 

    std::wofstream * OpenLoggerStreamImpl(string filename) 
    { 
     if(loggerStream == NULL) 
     { 
      loggerStream = new std::wofstream(filename); 
     } 
     return loggerStream; 
    } 

public: 
    LoggerImpl() : loggerStream(NULL) 
    { 
    } 

    std::wofstream * OpenLoggerStream(string filename) 
    { 
     return OpenLoggerStreamImpl(filename); 
    } 

    void DoSomethingWithLoggerStream() 
    { 
     if(loggerStream == NULL) 
     { 
      throw Exception("Aye, Caramba! Logging stream wasn't open yet!"); 
     } 

     // Do whatever you need with loggerStream 
    } 
}; 
+0

OP에서 초보자 C++ 상태에 대해 생각해 보면,'LoggerImpl'의 소멸자에서'loggerStream'을 삭제해야한다고 지적하겠습니다. 또는 범위를 벗어난 포인터를 자동으로 정리하는 방법에 대한 내 대답을 참조하십시오. – Anthony

4

이유는 기본 생성자와 std::wofstream 나중에 단지 open() 파일을 생성하지? 포함 된 객체의 수명을 바인딩하는 것이 올바른 접근 방법입니다.

C++ 11에서 당신은 또한 union에 생성자와 객체를 넣을 수 있습니다. 단점은 물론 union 회원의 평생 관리를 대신해야한다는 것입니다. 그러나이 방법을 사용하면 나중에 특정 구성원의 구성을 연기 할 수 있습니다. 아래 코드에서 new의 사용은 실제로는 배치 새이며, 적절한 위치에 객체를 구성합니다. 다음은 예입니다.

#include <iostream> 
#include <fstream> 
#include <new> 

class foo 
{ 
    bool constructed; 
    union helper { 
     helper() {} 
     ~helper() {} 
     std::ifstream stream; 
    } member; 
public: 
    foo(): constructed() {} 
    ~foo() { 
     if (constructed) { 
      using std::ifstream; 
      this->member.stream.~ifstream(); 
     } 
    } 
    void open(std::string const& name) { 
     new (&this->member.stream) std::ifstream(name); 
     constructed = true; 
    } 
    std::streambuf* rdbuf() { 
     return this->member.stream.rdbuf(); 
    } 
}; 

int main() 
{ 
    foo f; 
    f.open("foo.cpp"); 
    std::cout << f.rdbuf(); 
} 
+0

이것은 포인터를 사용하지 않고 구성원 구성을 연기하는 방법에 실제로 응답하는 유일한 게시물입니다 (그리고 그에 따라 힙 할당 메모리가 있음). –