编译器生成的赋值运算符是否不安全? P>我理解C++编译器生成赋值操作符: struct X { std::vector<int> member1; std::vector<int> member2; X& operator=(const X& other) { member1 = other.member1; member2 = other.member2; } }; struct X{ std::载体成员1; std::载体成员2; X运算符=(常量X和其他){ member1=其他。member1; 成员2=其他成员2; } };

编译器生成的赋值运算符是否不安全? P>我理解C++编译器生成赋值操作符: struct X { std::vector<int> member1; std::vector<int> member2; X& operator=(const X& other) { member1 = other.member1; member2 = other.member2; } }; struct X{ std::载体成员1; std::载体成员2; X运算符=(常量X和其他){ member1=其他。member1; 成员2=其他成员2; } };,c++,C++,这个例外不安全吗?如果member2=other.member2抛出,则原始分配的副作用不会撤消。使用系统: 不准扔 强有力的保证--操作完成或完全回滚 基本保证--不变量被保留,没有资源泄漏 不保证 如果对象的每个成员都提供基本异常保证或“更好”,并且如果对象不变量没有成员内依赖关系,则编译器生成的赋值运算符具有基本异常保证 如果每个成员的任务也有无掷骰保证,则它有无掷骰保证 它很少(如果有的话)有强有力的保证,这可能就是您所说的“异常不安全” 复制交换习惯用法很流行,因为编写无抛出swa

这个例外不安全吗?如果
member2=other.member2
抛出,则原始分配的副作用不会撤消。

使用系统:

  • 不准扔
  • 强有力的保证--操作完成或完全回滚
  • 基本保证--不变量被保留,没有资源泄漏
  • 不保证
如果对象的每个成员都提供基本异常保证或“更好”,并且如果对象不变量没有成员内依赖关系,则编译器生成的赋值运算符具有基本异常保证

如果每个成员的任务也有无掷骰保证,则它有无掷骰保证

它很少(如果有的话)有强有力的保证,这可能就是您所说的“异常不安全”

复制交换习惯用法很流行,因为编写无抛出
swap
通常很容易,而且构造函数应该已经提供了强大的异常保证。结果是一个
运算符=
,具有强异常保证。(在
move
的情况下,它是伪强的,因为输入通常不会回滚,但它是一个右值)

如果还按值复制,有时可以将
operator=
升级为no-throw(唯一的例外可能是在构造参数时)

在某些情况下,
Foo
的一些构造函数是
noexcept
,而另一些则不是:通过按值获取另一个,我们提供了我们所能提供的最佳异常保证(因为
=
的参数有时可以直接构造,可以通过省略或通过
{}
直接构造)


由于以下几个原因,该语言(至少在此时)在强大的保证下实现拷贝交换
操作符=
,是不实际的。首先,C++操作“只为你所用的东西付费”,复制交换比会员复制更昂贵。其次,
swap
目前不是核心语言的一部分(有一些建议添加
操作符:=:
并将其折叠起来)。第三,与C++的以前版本和C.

< P> <强> 2014年6月4日编辑< /强>

的反向兼容性 我最初的回答是基于我的理解,最初的海报要求一个保证不会抛出异常的赋值操作符。根据各种评论者的说法,很明显,只要对象在异常上保持不变,异常就可以了

建议的方法是通过临时变量和std::swap()

事实上,我们不能相信swap()不会抛出异常,除非我们对对象的组件有一点了解

为了确保swap()永远不会抛出,我们需要将成员对象设置为和

在给出的示例中,使用C++11或更高版本的编译器,std::vector是
移动可分配和移动可构造,所以我们是安全的。然而,作为一种通用解决方案,我们始终需要了解我们所做的任何假设,并检查它们是否成立。

它不提供强有力的例外保证。这和不安全开始不是一回事。不会有内存泄漏或诸如此类的事情。@BenjaminLindley:我认为不提供强保证本质上是不安全的,在涉及非强函数时,程序员当然应该特别考虑。嗯。。。标准中关于部分赋值的保证是什么?@DeadMG:那么你有答案了,没有?但你可能应该在你的问题中明确“异常不安全”对你意味着什么。我不确定这里的问题是什么。它是“赋值运算符是这样生成的吗?”,还是“我知道赋值运算符是这样生成的;这是否允许异常将对象保留为半赋值的?”,还是“我知道赋值运算符是这样生成的,这允许异常将对象保留一半赋值;这被认为是不安全的异常吗?“我希望它不会捕获异常,而是复制1到2个temp,如果可以,然后交换它们(不会抛出)。如果复制抛出对象,则保持不变。如果成员是POD(纯旧数据)然后不会抛出任何异常,一切都是安全的。如果成员可以抛出异常,则意味着分配可能会失败。即使您将temp和swap()弄得一团糟你可能仍然会失败。那你该怎么办?@MichaelJ如果你使用临时变量,并且它在临时变量的构造过程中失败,那么你自己的实例还不会被修改。因此,你什么也不做。调用方可以捕获异常(如果合适的话),也可以不这样做。不管怎样,这都不是你的问题。如果它在你自己的实例之间的交换过程中失败临时的,你有一个定义不好的交换,因为那应该几乎不需要抛出,在这种情况下,修复交换函数。临时的交换应该永远不会抛出,或者失败!它应该归结为重新分配指针你的答案似乎是由这样一个想法指导的,即赋值操作符不抛出Exception但这不是重点。您的解决方案(这是一个糟糕的想法,imo)甚至不能保证这一点,因为异常不一定来自
std::exception
(尽管它们应该)。目标是,如果抛出异常,可以保证对象不被修改。
void swap( Foo& other ) noexcept; // implement this
Foo& operator=( Foo const& f ) {
  Foo tmp(f);
  swap( tmp );
  return *this;
}
Foo& operator=( Foo && f ) {
  Foo tmp(std::move(f));
  swap( tmp );
  return *this;
}
Foo& operator=( Foo f ) noexcept {
  swap( f );
  return *this;
}
X& X::operator=(const X& other)
{
    // assign to temps.  If this throws, the object
    // has not changed.
    auto m1 = other.member1;
    auto m2 = other.member2;

    // the theory is, that swap won't throw
    // can we rely on that?
    std::swap(m1, member1);
    std::swap(m2, member2);

    return *this;
}