提问人:Dan 提问时间:7/13/2021 更新时间:7/13/2021 访问量:353
为什么 std::sort 抱怨已删除的副本 ctor?
Why is std::sort complaining about a deleted copy ctor?
问:
假设我们有一个简单的类,它包含一个:std::string
class StringWrapper {
public:
const std::string s;
StringWrapper(const std::string s)
: s(s) {}
// We want this to be moveable but not copyable
~StringWrapper() = default;
StringWrapper(const StringWrapper&) = delete;
StringWrapper& operator=(const StringWrapper&) = delete;
StringWrapper(StringWrapper&&) noexcept = default;
StringWrapper& operator=(StringWrapper&&) = default;
};
在这里,我们试图使类可移动,但不可复制。我知道成员变量通常会阻止生成默认的移动 ctor,但在这里我们尝试显式生成它 - 这至少可以编译。const
现在我们尝试对 a 进行排序(比较函数在这里并不重要):std::vector<StringWrapper>
std::vector<StringWrapper> strings;
std::sort(strings.begin(), strings.end(), [](auto const& a, auto const& b) { return true; });
这无法编译,但错误非常隐晦:
1>...\include\algorithm(7419,25): error C2280: 'StringWrapper &StringWrapper::operator =(const StringWrapper &)': attempting to reference a deleted function
1>...src\example.cpp(476): message : see declaration of 'StringWrapper::operator ='
1>...src\example.cpp(476,24): message : 'StringWrapper &StringWrapper::operator =(const StringWrapper &)': function was explicitly deleted
1>...\include\algorithm(7541): message : see reference to function template instantiation '_BidIt std::_Insertion_sort_unchecked<_RanIt,_Pr>(const _BidIt,const _BidIt,_Pr)' being compiled
1> with
1> [
1> _BidIt=StringWrapper *,
1> _RanIt=StringWrapper *,
1> _Pr=myFunc::<lambda_8668e50965d967f7b587b72f59fcb0cf>
1> ]
1>...\include\algorithm(7571): message : see reference to function template instantiation 'void std::_Sort_unchecked<StringWrapper*,_Fn>(_RanIt,_RanIt,int,_Pr)' being compiled
1> with
1> [
1> _Fn=myFunc::<lambda_8668e50965d967f7b587b72f59fcb0cf>,
1> _RanIt=StringWrapper *,
1> _Pr=myFunc::<lambda_8668e50965d967f7b587b72f59fcb0cf>
1> ]
1>...src\example.cpp(488): message : see reference to function template instantiation 'void std::sort<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<_Ty>>>,myFunc::<lambda_8668e50965d967f7b587b72f59fcb0cf>>(const _RanIt,const _RanIt,_Pr)' being compiled
1> with
1> [
1> _Ty=StringWrapper,
1> _RanIt=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<StringWrapper>>>,
1> _Pr=myFunc::<lambda_8668e50965d967f7b587b72f59fcb0cf>
1> ]
1>...\include\algorithm(7422,28): error C2280: 'StringWrapper &StringWrapper::operator =(const StringWrapper &)': attempting to reference a deleted function
1>...src\example.cpp(476): message : see declaration of 'StringWrapper::operator ='
1>...src\example.cpp(476,24): message : 'StringWrapper &StringWrapper::operator =(const StringWrapper &)': function was explicitly deleted
1>...\include\algorithm(7425,24): error C2280: 'StringWrapper &StringWrapper::operator =(const StringWrapper &)': attempting to reference a deleted function
1>...src\example.cpp(476): message : see declaration of 'StringWrapper::operator ='
1>...src\example.cpp(476,24): message : 'StringWrapper &StringWrapper::operator =(const StringWrapper &)': function was explicitly deleted
具体来说,它表明正在尝试引用已删除的副本 ctor,但我不知道为什么会这样;我希望只使用移动操作。std::sort
std::sort
谁能向我解释一下这是怎么回事?
答:
3赞
Jon Reeves
7/13/2021
#1
这在注释中已经介绍过了,但值得注意的是,对于后代来说,使用关键字并不能保证编译器总是会尝试创建特殊成员的默认实现。这(像往常一样)在 cpppreference 上的移动赋值运算符一节中得到了很好的解释。default
如果满足以下任一条件,则类 T 的隐式声明或默认移动赋值运算符定义为已删除:
- T 有一个非静态数据成员,即 。
const
编译器也会像这里一样抱怨这种情况。例如 clang:
warning: explicitly defaulted move assignment operator is implicitly deleted [-Wdefaulted-function-deleted]
StringWrapper& operator=(StringWrapper&&) = default;
^
note: move assignment operator of 'StringWrapper' is implicitly deleted because field 's' has no move assignment operator
const std::string s;
请注意,这是一个警告,而不是一个错误,这就是你最终遇到这种情况的方式。一般来说,最好不要假设关键字允许您绕过语言限制。default
上一个:用 C++ 编写 PNG
下一个:“三法则”的实施出了问题
评论
operator=
const
= default
:在这种情况下,默认的移动运算符也会被删除。StringWrapper
对象不可排序,因为它们不可赋值,也不可移动赋值。您需要提供可移动的实现。operator<