提升::可选与标准::不可复制对象的可选

boost::optional vs std::optional for non copyable objects

本文关键字:对象 可复制 提升 标准      更新时间:2023-10-16

我尝试从VS2015更新到VS2017,但下面的代码在较新版本中不起作用。如您所见,定义了一个移动构造函数,它会自动删除复制构造函数。

#include <boost/optional.hpp>
#include <vector>
struct Foo {
Foo() {}
Foo(Foo&& other) {}
};
int main() {
std::vector<boost::optional<Foo>> foos;
foos.resize(42);
return 0;
}

编译错误为

1>...boostdistincludeboost-1_66boostoptionaloptional.hpp(384): error C2280: 'Foo::Foo(const Foo &)': attempting to reference a deleted function
1>...main.cpp(7): note: compiler has generated 'Foo::Foo' here
1>...boostdistincludeboost-1_66boostoptionaloptional.hpp(383): note: while compiling class template member function 'void boost::optional_detail::optional_base<T>::construct(const Foo &)'
1>        with
1>        [
1>            T=Foo
1>        ]
1>...boostdistincludeboost-1_66boostoptionaloptional.hpp(181): note: see reference to function template instantiation 'void boost::optional_detail::optional_base<T>::construct(const Foo &)' being compiled
1>        with
1>        [
1>            T=Foo
1>        ]
1>...boostdistincludeboost-1_66boostoptionaloptional.hpp(831): note: see reference to class template instantiation 'boost::optional_detail::optional_base<T>' being compiled
1>        with
1>        [
1>            T=Foo
1>        ]
1>...msvc14.12.25827includevector(1902): note: see reference to class template instantiation 'boost::optional<Foo>' being compiled
1>...msvc14.12.25827includevector(1901): note: while compiling class template member function 'boost::optional<Foo> *std::vector<boost::optional<Foo>,std::allocator<_Ty>>::_Udefault(boost::optional<Foo> *,const unsigned __int64)'
1>        with
1>        [
1>            _Ty=boost::optional<Foo>
1>        ]
1>...msvc14.12.25827includevector(1528): note: see reference to function template instantiation 'boost::optional<Foo> *std::vector<boost::optional<Foo>,std::allocator<_Ty>>::_Udefault(boost::optional<Foo> *,const unsigned __int64)' being compiled
1>        with
1>        [
1>            _Ty=boost::optional<Foo>
1>        ]
1>...main.cpp(10): note: see reference to class template instantiation 'std::vector<boost::optional<Foo>,std::allocator<_Ty>>' being compiled
1>        with
1>        [
1>            _Ty=boost::optional<Foo>
1>        ]
1>...main.cpp(7): note: 'Foo::Foo(const Foo &)': function was implicitly deleted because 'Foo' has a user-defined move constructor

现在有趣的是,当我使用std::optional而不是boost::optional时,它确实可以编译。我真的不确定问题是什么以及应该责怪谁:我、Boost、微软、C++ 标准?有人知道发生了什么吗?

这是一个已知问题吗?这是提升中的错误还是它不起作用是正确的?

这似乎是 STL 实现的一个问题。

从最新草案 n4700:

26.2.1 一般容器要求[container.requirements.general]定义了DefaultInsertableMoveInsertable,并部分声明:

TCopyInsertableX意味着,除了TMoveInsertableX之外,以下表达式的格式正确:

allocator_traits<A>::construct(m, p, v)

其计算导致以下后置条件成立:v的值保持不变,等效于*p

(在这种情况下,Tboost::optional<Foo>Xstd::vector<T>

显然,TDefaultInsertableMoveInsertable,但不是CopyInsertable.

26.3.11.3vector容量[矢量容量]部分声明:

void resize(size_type sz);

效果:如果sz < size(),则从序列中擦除最后size() - sz个元素。否则,sz - size()默认插入的元素追加到序列中。

要求:TMoveInsertableDefaultInsertable*this

备注:如果抛出的异常不是由非CopyInsertableT的移动构造函数引发的,则不会产生任何影响。

虽然我没有C++11或C++14的正式副本,但根据工作副本,C++11没有">备注:">段落,并且有一个略有不同的">要求:">段落:

要求:TCopyInsertable*this

因此,foos.resize(42)在 C++11 中格式不正确,但在 C++14 中应该格式良好,因为满足TMoveInsertableDefaultInsertable向量的要求。

我已经证实了@patatahooligan的评论,即将noexcept添加到Foo移动构造函数中允许代码在 Clang 和 g++ 7.2.0 中编译。但是,除非我误读了标准,否则不要求非CopyInsertableT的移动构造函数除外;事实上,该标准似乎允许非CopyInsertableT的移动构造函数抛出异常的可能性,在这种情况下,不能保证是否存在效果。

更新我已经提交了 GCC 错误 83981 和 83982。