2011-01-31 2 views
7

클래스 인스턴스가 rvalues ​​(예 : 임시)로만 사용되도록 제한 할 수 있습니까?임시 인스턴스로만 사용되도록 클래스 인스턴스를 제한 할 수 있습니까?

예를 들어, 나는 Wrapper 클래스를 가지고 있으며 그 생성자는 A const&을 취해이 참조를 멤버에 저장합니다. Wrapper 인스턴스의 수명이 A 인스턴스의 수명보다 길어서는 안되기 때문에 위험합니다. Wrappertemporary 인 경우 문제가 없습니다.

+1

인스턴스가 힙이 아닌 스택에 만 생성되도록 허용 할 수 있습니까? –

+0

아니요, 임시 사용자로만 사용하십시오. 스택 상에 그러한 인스턴스를 생성하는 것은 여전히 ​​위험합니다. –

+1

때때로 최상의 예방 조치는 문서에서 "do not do X"의 주석입니다. –

답변

3

나는 그것이 안전 할 것이라고 생각하지 않는다 :이 경우

const A &a = YourClass(tmp); 

YourClass 당신이 임시 인스턴스를 허용하는 찾고있는 클래스, tmp는 생성자에 전달할 임시 값입니다.
임시 (예 : a)에 대한 상수 참조를 가질 수는 있지만 임시 자체 (예 : YourClass)에는 해당 표현 후에 더 이상 유효하지 않은 tmp에 대한 참조가 있습니다 평가됩니다.

+0

정확히 내가 생각하고 있었던 것. 구문 론적으로 할 수 있지만 const 참조를 바인딩 할 수 있다는 사실은 어쨌든 위험한 방식으로 수명을 연장합니다. – CashCow

0

예, 가능합니다.

생성자와 일반 복사 생성자/할당을 private으로 지정하지만 r 값 이동 의미 (C++ 0x)를 public으로 만듭니다.

임시 또는 친구 생성자를 만들면됩니다.

2003 C++에서는 const 참조에 바인딩 할 수도 있습니다.

물론 당신은 당신의 const 레퍼런스가 아마 성명 이후에 무효화 될 것입니다.

+0

음 ... 그게 효과가 있다고 확신합니까? 유일한 public 생성자가 rvalue 참조 일 경우 클래스의 인스턴스를 인스턴스화 할 수 없다고 생각합니다. 따라서 rvalue 참조 생성자에 인스턴스를 전달할 수 없습니다. – peoro

+0

그는 제안했습니다. rvalue를 반환하는 friend 함수를 사용합니다. – Puppy

+2

이것은'T const & ref = T :: factory (blah);를 방지하지 않는다. : 이동 의미는 값에 의한 반환 (생략 가능)과 const가 수명을 연장하도록 허용한다. 내가 뭘 놓치고 있니? –

1

컴파일 시간에이 작업을 강요하지 않아도됩니다. 너무 제한적이어서 클래스의 유용성을 제한하는 모서리의 경우가 있기 때문에 valgrind 또는 Purify과 같은 도구를 감쌀 수 있으므로 유효하지 않은 참조가 사용 된 장소.

3

나는 이것을하기를 원한다해도 정말 나쁜 디자인의 징후라고 생각합니다.

그러나 모든 생성자를 비공개로 설정하고 rvalue를 반환하는 friend 함수를 만들 수 있습니다. 그 트릭을해야합니다.

+0

어떻게 작동합니까? 사본 ctor 또는 이동 ctor는 값을 생략해도 액세스 할 수 있어야 액세스 할 수 있어야합니다. –

+0

그가 참조로 결과를 가져가는 것은 아닙니다. – Puppy

+0

참조로 결과를 가져 오는 경우에도 : http://codepad.org/97oaJNfl 및 N3225 §12.2p1, "... prvalue에 대한 참조 바인딩, prvalue 반환 ... 복사/이동 생성자가 호출되지 않더라도 모든 접근성과 같은 의미 론적 제한이 충족되어야한다. " –

3

정확한 대답은 아니지만 약한 포인터에 대해 생각해 보셨습니까? (예 : boost::weak_ptr). 이 경우 원본 Ashared_ptr에 보관되고 Wrapper 생성자는 weak_ptr을 허용합니다. 이 접근법의 깔끔한 점은 weak_ptr을 사용하기 전에 lock()을 시도하면 shared_ptr이됩니다. 실패 할 경우 A이 사라지고 Wrapper이 작동하지 않는다는 것을 알게됩니다. 그러나 정상적으로 처리됩니다. ..

0

클래스에 공용 데이터 멤버가 없으면이 작업이 수행 될 수 있습니다.

기본적으로 래퍼의 구성을 제한하는 것이 아니라 (임시 보관 값인 경우에만 사용 가능)을 사용할 수 있습니다.모두 메서드를 오버로드하고 const &을 참조하는 메서드를 삭제하거나 비공개로 만들어이 작업을 수행 할 수 있습니다.

class Wrapper 
{ 
public: 
    Wrapper() = default; 
    Wrapper(const std::string& name) : name(name) {} 
    void process() && { std::cout << "Greetings from " << name << std::endl; } 
    // Only temporary instances of this class are allowed! 
    void process() const & = delete; 

private: 
    std::string name; 
}; 

그리고 일부 사용 사례 :

Wrapper("John").process(); // intended use case 
Wrapper j; // create whatever you want 
j.process(); // error C2280: 'void Wrapper::process(void) const &': attempting to reference a deleted function 
std::move(j).process(); // this is still possible 
const Wrapper& t = Wrapper(); // bind the temporary to a const reference - not a problem because ... 
t.process(); // error C2280: 'void Wrapper::process(void) const &': attempting to reference a deleted function 

명백한 단점은 다음과 같습니다

  • 당신은 모든 공공 멤버 함수를 오버로드 할

    다음은 간단한 예입니다.

  • 오류 메시지가 지연되어 매우 유익하지 않습니다.

비슷한 점이 표준에서 수행되었습니다. std :: reference_wrapper에 대한 make 루틴 do not accept temporaries. 그들은 다른 미묘 고려

참고 : 과부하는 const를 T & & 대신 T & &를 사용합니다. 이 경우에도 중요 할 수 있습니다. 래퍼가 의도적으로 noncopyable 수 있도록 설계되어 예를 들어, 당신은이 경우

const Wrapper make_wrapper(); 

대신

Wrapper make_wrapper(); 

같은 루틴을 사용, 당신은 대체 할 수 있습니다

void process() &&; 

void process() const &&; 
관련 문제