2017-12-05 15 views
-1

저는 Java/PHP에서 제공하는 C++을 처음 접했습니다. 기본적으로 가상 클래스 인스턴스 (기본 클래스)에 대한 고유/공유 포인터에 대한 참조를 보유 할 컨테이너 클래스를 만들어야합니다. 이 코드를 컴파일 할 수 없습니다 (MSVC 2015 사용). 여기 컨테이너 클래스의 shared_ptr/unique_ptr에 가상 객체 사용

error C2280: 'std::unique_ptr<Base,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)': attempting to reference a deleted function 

문제를 재현하는 샘플 응용 프로그램입니다 :

컴파일러 오류는

#include <iostream> 
#include <memory> 

class Base { 
    public: 
     virtual void foo() const = 0; 
     virtual void bar() const = 0; 
}; 

class Derived : public Base { 
    public: 
     void foo() const override { 
      std::cout << "foo" << std::endl; 

     }; 

     void bar() const override{ 
      std::cout << "bar" << std::endl; 
     }; 
}; 

class ContainerUnique { 
    public: 
     ContainerUnique() { 
      ptr = nullptr; 
     } 

     void assignPtr(const Base &instance) { 
      auto ptr = std::make_unique<Base>(instance); 
      ptr.swap(ptr); 
     }; 

     std::unique_ptr<Base> getPtr() { 
      return ptr; 
     }; 

    private: 
     std::unique_ptr<Base> ptr; 
}; 

class ContainerShared { 
    public: 
     ContainerShared() { 
      ptr = nullptr; 
     } 

     void assignPtr(const Base &instance) { 
      auto ptr = std::make_shared<Base>(instance); 
      ptr.swap(ptr); 
     }; 

     std::shared_ptr<Base> getPtr() { 
      return ptr; 
     }; 

    private: 
     std::shared_ptr<Base> ptr; 
}; 

int main() { 
    Derived derived1 = Derived(); 
    Derived derived2 = Derived(); 

    ContainerUnique cu = ContainerUnique(); 
    ContainerShared cs = ContainerShared(); 

    cu.assignPtr(derived1); 
    cs.assignPtr(derived2); 

    std::unique_ptr<Base> uptr = cu.getPtr(); 
    std::shared_ptr<Base> sptr = cs.getPtr(); 

    return 0; 
} 

+5

'표준을 :: getPtr unique_ptr()'카피를 돌려줍니다. 'unique_ptr'을 복사 할 수 없습니다. 당신이 달성하고자하는 의미가 무엇인지 모르겠습니다. 'getPtr'는 소유권을 공유 할 것으로 예상됩니까? 그렇다면'unique_ptr'을 사용할 수 없습니다. 그렇지 않은 경우 스마트 포인터를 반환하지 마십시오. –

+0

오류와 관련이 없습니다 : 재정의 된 기본 생성자가 필요하지 않으므로이 경우'ptr.swap '(또는 같은 이름의 임시 변수)을 사용하면 안됩니다. 단지'ptr = std :: make_unique (인스턴스);'충분하다 – UnholySheep

+0

@ UnholySheep. 컴파일러는'오류 C2259 : 'Base': 추상 클래스를 인스턴스화 할 수 없다' –

답변

0

당신은 오브젝트 소유권에 대해 생각해야 조언을 주시기 바랍니다, 그리고 개체가 어디에 살고 (스택 또는 힙), 어느 쪽도 자바로 집중해야했을지도 모릅니다.

ContainerUniqueunique_ptr 회원을 가지고 있기 때문에 지적한 개체를 소유하고 있다고 가정합니다. 삭제 의무가 있습니다. derived1이 스택에 있으므로 아무 것도 소유 할 필요가 없으며 삭제할 수 없기 때문에 이것은 나머지 부분과 일치하지 않습니다. 대신, 우리는 힙에 derived1를 만든 가정 : 그것은 관리가 필요 있도록 힙을 생성하고, unique_ptr에의 포인터를 저장하여 객체를 소유하는 우리를 식별

auto derived1 = std::make_unique<Derived>(); 

합니다. 인터페이스 또는 소유권 의도 된 변화를 반영하기 위해 호출 사이트에서 아무것도, 우리가 원시 참조 또는 포인터를 가지고가는 경우에

// Interface 
void ContainerUnique::assignPtr(std::unique_ptr<Base> instance); 
// Call site 
cu.assignPtr(std::move(derived1)); 

하십시오 unique_ptr로 소유권을 이전하기 위해, 우리는 인터페이스를 조정할 수 있습니다. 참조 자료를 가져 와서 std::make_unique으로 전화를 걸면 자료를 복사하고 자료의 사본을 만듭니다 (파생 된 데이터가 손실 됨). unique_ptr을 사용하는 것은 아마도 소유권 양도를 전달하는 가장 명확한 방법 일 것입니다.

함께 퍼팅 :

#include <memory> 

struct Base { 
    virtual void foo() const = 0; 
    virtual void bar() const = 0; 
}; 

struct Derived : Base { 
    void foo() const override { } 
    void bar() const override { } 
}; 

class ContainerUnique { 
    public: 
     void assignPtr(std::unique_ptr<Base> instance) { 
      ptr.swap(instance); 
     }; 

     std::unique_ptr<Base> getPtr() { 
      return std::move(ptr); 
     }; 

    private: 
     std::unique_ptr<Base> ptr; 
}; 

int main() { 
    auto derived1 = std::make_unique<Derived>(); 
    auto cu = ContainerUnique(); 
    cu.assignPtr(std::move(derived1)); 
    auto uptr = cu.getPtr(); 
} 
관련 문제