std :: unique_ptr을 함수에 어떻게 전달할 수 있습니까?


101

std::unique_ptr함수에를 어떻게 전달할 수 있습니까? 다음과 같은 수업이 있다고 가정 해 보겠습니다.

class A
{
public:
    A(int val)
    {
        _val = val;
    }

    int GetVal() { return _val; }
private:
    int _val;
};

다음은 컴파일되지 않습니다.

void MyFunc(unique_ptr<A> arg)
{
    cout << arg->GetVal() << endl;
}

int main(int argc, char* argv[])
{
    unique_ptr<A> ptr = unique_ptr<A>(new A(1234));
    MyFunc(ptr);

    return 0;
}

std::unique_ptr함수에를 전달할 수없는 이유는 무엇 입니까? 확실히 이것이 구조의 주요 목적입니까? 또는 C ++위원회는 원시 C 스타일 포인터로 돌아가서 다음과 같이 전달하도록 의도 했습니까?

MyFunc(&(*ptr)); 

그리고 가장 이상하게도 이것이 통과하는 데 적합한 방법 인 이유는 무엇입니까? 끔찍하게 일관성이 없어 보입니다.

MyFunc(unique_ptr<A>(new A(1234)));

7
소유하지 않은 원시 포인터 인 한 원시 C 스타일 포인터로 "폴백"하는 것은 잘못된 것이 아닙니다. 'ptr.get ()'을 선호 할 수도 있습니다. null 허용 여부가 필요하지 않은 경우 참조가 선호됩니다.
크리스 드류

답변:


149

여기에는 기본적으로 두 가지 옵션이 있습니다.

참조로 스마트 포인터 전달

void MyFunc(unique_ptr<A> & arg)
{
    cout << arg->GetVal() << endl;
}

int main(int argc, char* argv[])
{
    unique_ptr<A> ptr = unique_ptr<A>(new A(1234));
    MyFunc(ptr);
}

스마트 포인터를 함수 인수로 이동

이 경우 어설 션이 유지됩니다!

void MyFunc(unique_ptr<A> arg)
{
    cout << arg->GetVal() << endl;
}

int main(int argc, char* argv[])
{
    unique_ptr<A> ptr = unique_ptr<A>(new A(1234));
    MyFunc(move(ptr));
    assert(ptr == nullptr)
}

@VermillionAzure : 참조하는 기능은 일반적으로 고유하지 않고 복사 불가능이라고합니다.
빌 린치

1
감사. 이 경우에는 인스턴스를 만들고 몇 가지 작업을 수행 한 다음 다른 사람에게 소유권을 넘겨주고 싶었습니다. move ()가 완벽 해 보입니다.
user3690202

7
unique_ptr함수가 이동하거나 이동할 수없는 경우 에만 참조로 전달해야 합니다. 그리고 그것은 rvalue 참조 여야합니다. 소유권의 의미에 대해 아무것도 요구하지 않고 물체를 관찰하기 위해, 같은 참조를 사용 A const&하거나 A&.
Potatoswatter

14
CppCon 2014에 대한 Herb Sutters 강연을 들어보세요. 그는 unique_ptr <>에 대한 참조를 전달하는 것을 강력히 권장하지 않습니다. 핵심은 소유권을 다룰 때 unique_ptr <> 또는 shared_ptr <>와 같은 스마트 포인터를 사용해야한다는 것입니다. 다음은 슬라이드를 찾을 수 있습니다 www.youtube.com/watch?v=xnqTKD8uD64를 참조 github.com/CppCon/CppCon2014/tree/master/Presentations/...
schorsch_76

2
@Furihr : ptr이동 후의 가치를 보여주는 방법 일뿐 입니다.
Bill Lynch

28

당신은 그것을 가치로 전달하고 있으며, 이는 사본을 만드는 것을 의미합니다. 그다지 독특하지 않을까요?

값을 이동할 수 있지만 이는 객체의 소유권과 수명 제어를 함수에 전달하는 것을 의미합니다.

개체의 수명이 MyFunc에 대한 호출 수명 동안 존재하도록 보장되는 경우를 통해 원시 포인터를 전달하면됩니다 ptr.get().


18

unique_ptr함수에를 전달할 수없는 이유는 무엇 입니까?

unique_ptr이동 생성자는 있지만 복사 생성자는 없기 때문에 그렇게 할 수 없습니다 . 표준에 따르면 이동 생성자는 정의되어 있지만 복사 생성자는 정의되지 않은 경우 복사 생성자는 삭제됩니다.

12.8 클래스 객체 복사 및 이동

...

7 클래스 정의가 복사 생성자를 명시 적으로 선언하지 않으면 암시 적으로 선언됩니다. 클래스 정의가 이동 생성자 또는 이동 할당 연산자를 선언하는 경우 암시 적으로 선언 된 복사 생성자는 삭제 된 것으로 정의됩니다.

다음 unique_ptr을 사용하여 함수 에을 전달할 수 있습니다 .

void MyFunc(std::unique_ptr<A>& arg)
{
    cout << arg->GetVal() << endl;
}

다음과 같이 사용하십시오.

또는

void MyFunc(std::unique_ptr<A> arg)
{
    cout << arg->GetVal() << endl;
}

다음과 같이 사용하십시오.

std::unique_ptr<A> ptr = std::unique_ptr<A>(new A(1234));
MyFunc(std::move(ptr));

중요 사항

두 번째 메서드를 사용하는 경우 반환 ptr호출 후 포인터의 소유권이 없습니다 std::move(ptr).

void MyFunc(std::unique_ptr<A>&& arg) 다음과 같은 효과가있을 것입니다. void MyFunc(std::unique_ptr<A>& arg)둘 다 참조이기 때문에 .

첫 번째 경우 ptr에는를 호출 한 후에도 여전히 포인터의 소유권이 MyFunc있습니다.


6

으로 MyFunc소유권을하지 않습니다, 그것을 가지고 더 좋을 것이다 :

void MyFunc(const A* arg)
{
    assert(arg != nullptr); // or throw ?
    cout << arg->GetVal() << endl;
}

이상

void MyFunc(const A& arg)
{
    cout << arg.GetVal() << endl;
}

정말로 소유권을 갖고 싶다면 리소스를 이동해야합니다.

std::unique_ptr<A> ptr = std::make_unique<A>(1234);
MyFunc(std::move(ptr));

또는 r 값 참조를 직접 전달하십시오.

MyFunc(std::make_unique<A>(1234));

std::unique_ptr 소유자가 한 명뿐임을 보증하기 위해 의도적으로 사본이 없습니다.


이 답변에는 처음 두 사례에 대한 MyFunc 호출이 누락되었습니다. 사용 중인지 ptr.get()아니면 그냥 ptr함수에 전달 하는지 확실하지 않습니까?
taylorstine

MyFuncr- 값 참조를 전달 하기위한 의도 된 서명은 무엇입니까 ?
James Hirschorn

@JamesHirschorn : void MyFunc(A&& arg)r- 값 참조를
받습니다

@ Jarod42의 짐작 무슨하지만으로는 typedef int A[], MyFunc(std::make_unique<A>(N))오류 : 컴파일러 에러 제공 형 기준 잘못 초기화 'INT (&&)] 유형의 표현에서 "표준 : _ MakeUniq <INT []> :: __ 배열'{ aka 'std :: unique_ptr <int [], std :: default_delete <int []>>'} g++ -std=gnu++11충분히 최근입니까?
James Hirschorn

@ Jarod42 나는 ideone : ideone.com/YRRT24
James Hirschorn

4

unique_ptr함수에를 전달할 수없는 이유는 무엇 입니까?

복사 할 수는 있지만 복사 할 수 std::unique_ptr<>는 없습니다. 복사 구성이 불가능 하기 때문 입니다.

확실히 이것이 구조의 주요 목적입니까?

무엇 std::unique_ptr<>보다도은 고유 한 소유권 을 명확하게 표시하도록 설계되었습니다 (와 반대 std::shared_ptr<>).

그리고 가장 이상하게도 이것이 통과하는 데 적합한 방법 인 이유는 무엇입니까?

이 경우 복사 구성이 없기 때문입니다.


답변 해 주셔서 감사합니다. 흥미롭게도 마지막 전달 방법이 복사 생성자를 사용하지 않는 이유를 설명해 주시겠습니까? unique_ptr의 생성자를 사용하면 스택에 인스턴스가 생성되고 복사 생성자를 사용하여 MyFunc ()에 대한 인수로 복사 될 것이라고 생각했을 것입니다. 내 기억이이 분야에서 약간 모호하다는 것을 인정하지만.
user3690202

2
rvalue이기 때문에 move-constructor가 대신 호출됩니다. 컴파일러는 확실히 이것을 최적화 할 것이지만 어쨌든.
Nielk 2015-06-18

0

unique_ptr고유 한 소유권을위한 것이므로 인수로 전달하려면

MyFunc(move(ptr));

그러나 상태 후 것을 ptr에서이 main될 것입니다 nullptr.


4
"정의되지 않을 것입니다"-아니오, 널이거나 unique_ptr쓸모가 없습니다.
TC

0

std::unique_ptr<T>함수에 값으로 전달 하는 것은 여러분이 언급 unique_ptr했듯이 복사 할 수 없기 때문에 작동 하지 않습니다.

이건 어때?

std::unique_ptr<T> getSomething()
{
   auto ptr = std::make_unique<T>();
   return ptr;
}

이 코드는 작동합니다


해당 코드가 작동하면 unique_ptr을 복사하지 않고 실제로 이동 의미 체계를 사용하여 이동하는 것 같습니다.
user3690202

반환 값 최적화 (RVO) 같아요 수 있습니다
Noueman Khalikine
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.