簡體   English   中英

具有顯式析構函數和std :: unique_ptr <>成員的類不能在std :: vector <>中使用?

[英]Class with explicit destructor and std::unique_ptr<> member can't be used in std::vector<>?

這段代碼

#include <memory>
#include <vector>

class Foo
{
public:
    ~Foo()
    {
    }

    std::unique_ptr<int> bar;
};

int main()
{
    std::vector<Foo> foos;
    foos.emplace_back();
}

在g ++中產生以下錯誤消息:

In file included from /usr/include/c++/4.8/memory:64:0,
                 from main.cpp:1:
/usr/include/c++/4.8/bits/stl_construct.h: In instantiation of ‘void std::_Construct(_T1*, _Args&& ...) [with _T1 = Foo; _Args = {Foo}]’:
/usr/include/c++/4.8/bits/stl_uninitialized.h:75:53:   required from ‘static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<Foo*>; _ForwardIterator = Foo*; bool _TrivialValueTypes = false]’
/usr/include/c++/4.8/bits/stl_uninitialized.h:117:41:   required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<Foo*>; _ForwardIterator = Foo*]’
/usr/include/c++/4.8/bits/stl_uninitialized.h:258:63:   required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = std::move_iterator<Foo*>; _ForwardIterator = Foo*; _Tp = Foo]’
/usr/include/c++/4.8/bits/stl_uninitialized.h:281:69:   required from ‘_ForwardIterator std::__uninitialized_move_if_noexcept_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = Foo*; _ForwardIterator = Foo*; _Allocator = std::allocator<Foo>]’
/usr/include/c++/4.8/bits/vector.tcc:415:43:   required from ‘void std::vector<_Tp, _Alloc>::_M_emplace_back_aux(_Args&& ...) [with _Args = {}; _Tp = Foo; _Alloc = std::allocator<Foo>]’
/usr/include/c++/4.8/bits/vector.tcc:101:54:   required from ‘void std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {}; _Tp = Foo; _Alloc = std::allocator<Foo>]’
main.cpp:17:23:   required from here
/usr/include/c++/4.8/bits/stl_construct.h:75:7: error: use of deleted function ‘Foo::Foo(const Foo&)’
     { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
       ^
main.cpp:4:7: note: ‘Foo::Foo(const Foo&)’ is implicitly deleted because the default definition would be ill-formed:
 class Foo
       ^
main.cpp:4:7: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]’
In file included from /usr/include/c++/4.8/memory:81:0,
                 from main.cpp:1:
/usr/include/c++/4.8/bits/unique_ptr.h:273:7: error: declared here
       unique_ptr(const unique_ptr&) = delete;

但是,如果我刪除~Foo()實現(和聲明),它編譯就好了。 可以觀察到相同的行為, main()看起來像這樣:

int main()
{
    auto f = Foo();
}
  • 為什么Foo調用Foo的拷貝構造函數? 難道不應該通過移動語義來實現這里的一切嗎?

  • 如果我刪除析構函數,為什么不隱式刪除它(復制構造函數)?

顯式析構函數聲明(和定義)禁止移動構造函數和移動賦值運算符的隱式聲明。 因此,唯一可以使用的是復制構造函數(無論什么都隱式聲明) - 但它被定義為已刪除,因為unique_ptr是不可復制的。 因此錯誤。

顯式默認它們 - 以及默認構造函數,因為你現在有一個用戶聲明的構造函數:

Foo() = default;
Foo(Foo&&) = default;
Foo& operator=(Foo&&) = default;

如果我刪除析構函數,為什么不隱式刪除它(復制構造函數)?

它仍被隱式刪除。 但是由於現在隱式聲明了一個移動構造函數,移動構造函數可以用於移動,而復制構造函數根本就沒有被使用。


相關標准引用(§12.8[class.copy] / p9,20,重點補充):

9如果類X的定義沒有顯式聲明一個移動構造函數,那么當且僅當一個移動構造函數被隱式聲明為默認值時

  • X沒有用戶聲明的復制構造函數,
  • X沒有用戶聲明的復制賦值運算符,
  • X沒有用戶聲明的移動賦值運算符,和
  • X沒有用戶聲明的析構函數

20如果類X的定義沒有顯式地聲明一個移動賦值運算符,那么當且僅當一個運算符默認時,它將被隱式聲明為默認值

  • X沒有用戶聲明的復制構造函數,
  • X沒有用戶聲明的移動構造函數,
  • X沒有用戶聲明的復制賦值運算符,和
  • X沒有用戶聲明的析構函數

Foo不可復制,因為它有一個成員unique_ptr Foo也不可移動,因為聲明用戶提供的析構函數會抑制默認移動構造函數/賦值的隱式生成。 如果你希望Foo是可移動的默認移動構造函數/賦值,那么編譯器將為你生成它們:

class Foo
{
public:
    ~Foo()
    {
    }

    Foo(Foo&&) = default;
    Foo& operator=(Foo&&) = default;

    std::unique_ptr<int> bar;
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM