提升::可选与标准::不可复制对象的可选
boost::optional vs std::optional for non copyable objects
我尝试从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]定义了DefaultInsertable
和MoveInsertable
,并部分声明:
T
CopyInsertable
X
意味着,除了T
被MoveInsertable
到X
之外,以下表达式的格式正确:allocator_traits<A>::construct(m, p, v)
其计算导致以下后置条件成立:
v
的值保持不变,等效于*p
。
(在这种情况下,T
boost::optional<Foo>
,X
std::vector<T>
。
显然,T
是DefaultInsertable
和MoveInsertable
,但不是CopyInsertable
.
26.3.11.3vector
容量[矢量容量]部分声明:
void resize(size_type sz);
效果:如果
sz < size()
,则从序列中擦除最后size() - sz
个元素。否则,sz - size()
默认插入的元素追加到序列中。要求:
T
应MoveInsertable
并DefaultInsertable
*this
。备注:如果抛出的异常不是由非
CopyInsertable
T
的移动构造函数引发的,则不会产生任何影响。
虽然我没有C++11或C++14的正式副本,但根据工作副本,C++11没有">备注:">段落,并且有一个略有不同的">要求:">段落:
要求:
T
应CopyInsertable
*this
。
因此,foos.resize(42)
在 C++11 中格式不正确,但在 C++14 中应该格式良好,因为满足T
MoveInsertable
并DefaultInsertable
向量的要求。
我已经证实了@patatahooligan的评论,即将noexcept
添加到Foo
移动构造函数中允许代码在 Clang 和 g++ 7.2.0 中编译。但是,除非我误读了标准,否则不要求非CopyInsertable
T
的移动构造函数除外;事实上,该标准似乎允许非CopyInsertable
T
的移动构造函数抛出异常的可能性,在这种情况下,不能保证是否存在效果。
更新我已经提交了 GCC 错误 83981 和 83982。
- 简单可复制与可简单复制
- 在什么条件下使用 std::memcpy 在对象之间复制是安全的?
- 我可以从列表中获取对象并复制它们,但如何删除我复制的对象?
- 是否可以将不可复制的成员用作使对象不可复制的替代方法?
- 如果 iostream 对象不可复制,为什么以下代码是合法的?
- 为什么我可以使用 memcpy 将一个对象变量复制到另一个对象变量
- reinterpret_cast,只读访问,简单的可复制类型,会出什么问题?
- 对于参加可复制和可移动类的访问者来说,应该有多少过载?
- 可变参数宏:无法通过"..."传递非平凡可复制类型的对象
- 为什么 std::atomic<std::string> 会给出微不足道的可复制错误?
- 我可以隐式地创建一个琐碎的可复制类型吗
- C :对象上的可复制视图
- 错误:无法通过'...'传递非平凡可复制类型的对象'class boost::filesystem::path'
- 使用realloc可以安全地重新分配琐碎的可复制对象的存储吗
- "constructing"一个带有memcpy的可复制对象
- 错误:无法通过`..`传递非普通可复制类型的对象
- 无法传递非普通可复制类型“const class mysqlpp::String”的对象
- 将std::memcpy用于非平凡可复制类型的对象
- 如何返回一个不可移动(但可复制)的对象
- 正在复制通常在c++ 14中定义的可复制对象