我的理解是C++ 隐式生成的赋值运算符执行成员方式的复制(这似乎也得到了这个答案的证实).但是,如果在成员副本期间抛出异常(例如,因为无法分配该成员的资源),被复制的对象是否会陷入无效状态?
换句话说,隐式生成的赋值运算符是仅实现基本保证,而不是强保证?
如果我们想要为我们的类副本提供强有力的保证,我们是否必须使用copy-and-swap惯用法手动实现赋值运算符?
此代码无法使用gcc 4.8.2(-std = c ++ 11)进行编译,但使用clang 3.4(trunk)编译(-std = c ++ 11):
#include <type_traits>
#include <vector>
struct X {
X& operator=(X&&) noexcept = default;
// adding noexcept this leads to an error in gcc, but works in clang:
// function ‘X& X::operator=(X&&)’ defaulted on its first
// declaration with an exception-specification that differs from the
// implicit declaration ‘X& X::operator=(X&&)’
std::vector<char> m;
};
// this assert holds, even without noexcept
static_assert(std::is_nothrow_move_assignable<X>::value,
"type-specification violation");
int main()
{
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这static_assert …
在VS 2010 SP1中,以下内容:
class Foo
{
public:
Foo() { }
Foo(Foo const&) = delete; // Line 365
Foo& operator=(Foo const&) = delete; // Line 366
};
Run Code Online (Sandbox Code Playgroud)
不编译.它抱怨说:
CPPConsole.cpp(365):错误C2059:语法错误:';'
CPPConsole.cpp(365):错误C2238:';'之前的意外标记
CPPConsole.cpp(366):错误C2059:语法错误:';'
CPPConsole.cpp(366):错误C2238:';'之前的意外令牌
这不支持吗?奇怪的是,Intellisense似乎认识到这种结构.它说"IntelliSense:function"Foo :: operator =(const Foo&)"(在第366行声明)无法引用 - 它是一个已删除的函数"
我错过了什么?
以下是实际问题的简化版本.Base::operator=(int)代码似乎不是调用,而是生成临时Derived对象并复制它.为什么不使用基本赋值运算符,因为函数签名似乎完全匹配?这个简化的示例没有显示任何不良影响,但原始代码在析构函数中具有副作用,导致各种破坏.
#include <iostream>
using namespace std;
class Base
{
public:
Base()
{
cout << "Base()\n";
}
Base(int)
{
cout << "Base(int)\n";
}
~Base()
{
cout << "~Base()\n";
}
Base& operator=(int)
{
cout << "Base::operator=(int)\n";
return *this;
}
};
class Derived : public Base
{
public:
Derived()
{
cout << "Derived()\n";
}
explicit Derived(int n) : Base(n)
{
cout << "Derived(int)\n";
}
~Derived()
{
cout << "~Derived()\n";
}
};
class Holder
{
public:
Holder(int n)
{
member …Run Code Online (Sandbox Code Playgroud) 最近,我跟着讨论了C++中表达式的赋值,如下例所示:
string s1, s2, s3;
(s1 + s2) = s3;
Run Code Online (Sandbox Code Playgroud)
使用C++ 11,可以将赋值运算符限制为左值引用(在左侧).当声明赋值运算符如下时,由于类型不兼容,编译器Clang拒绝带有错误消息的代码.
auto operator=(const string& rhs) & -> string&;
auto operator=(string&& rhs) & -> string&;
Run Code Online (Sandbox Code Playgroud)
我没有在任何地方见过这个.是否有充分的理由不为赋值运算符使用左值引用限定符(除了在大多数编译器中缺少支持)?
这个问题是关于历史(不是你目前对此事的看法).
在阅读关于为Swift删除对递增/递减运算符的支持的帖子时,我读了这样的文本"Swift已经偏离C,因为=,+ =和其他类似赋值的操作返回Void(由于多种原因)".
所以在过去的某个时候,开发人员有意识地决定将任务评估为无效,原因有些.
我正在寻找那些历史(现在)的原因.就像这个线程是关于Scala的历史原因一样.
如果我有一个,vector<bool> vec_bool那么我无法使用|=赋值运算符修改向量的内容.就是这条线
vec_bool[0] |= true;
vec_bool[0] |= vec_bool[1];
Run Code Online (Sandbox Code Playgroud)
给出编译错误,而行
bool a = false;
a |= true;
a |= vec_bool[0];
vec_bool[0] = vec_bool[0] | vec_bool[1];
vec_bool[0] = vec_bool[0] || vec_bool[1];
vector<int> vec_int(3);
vec_int[0] |= vec_int[1];
Run Code Online (Sandbox Code Playgroud)
不要.这是什么原因?
给出的错误(通过gcc)是:
TEST.CPP:21:17:错误:不对应的 '运营商| ='(操作数的类型是 '的std ::矢量::参考{又名的std :: _ Bit_reference}' 和 '布尔')
考虑一类需要复制的副本.副本中的绝大多数数据元素必须严格反映原始数据元素,但是有少数元素的状态不被保留且需要重新初始化.
从复制构造函数调用默认赋值运算符是不好的形式?
默认赋值运算符对于Plain Old Data(int,double,char,short)以及每个赋值运算符的用户定义类都表现良好.指针需要单独处理.
一个缺点是该方法使得赋值运算符瘫痪,因为不执行额外的重新初始化.也无法禁用赋值运算符的使用,从而通过使用不完整的默认赋值运算符打开用户创建损坏类的选项A obj1,obj2; obj2=obj1; /* Could result is an incorrectly initialized obj2 */.
a(orig.a),b(orig.b)...除了a(0),b(0) ...必须写之外,放宽要求是很好的.需要写入所有初始化两次会产生两个错误位置,如果double x,y,z要将新变量(例如)添加到类中,初始化代码需要在至少2个位置而不是1个位置正确添加.
有没有更好的办法?
在C++ 0x中有更好的方法吗?
class A {
public:
A(): a(0),b(0),c(0),d(0)
A(const A & orig){
*this = orig; /* <----- is this "bad"? */
c = int();
}
public:
int a,b,c,d;
};
A X;
X.a = 123;
X.b = 456;
X.c = 789;
X.d = 987;
A Y(X);
printf("X: %d %d %d %d\n",X.a,X.b,X.c,X.d); …Run Code Online (Sandbox Code Playgroud) 编译器是否为自我赋值生成了赋值操作符?
class T {
int x;
public:
T(int X = 0): x(X) {}
};
int main()
{
T a(1);
a = a;
}
Run Code Online (Sandbox Code Playgroud)
即使班级成员不是指针类型,我是否总是需要防止自我分配?
我的印象是阵列是不可复制的(或可分配的).
int x[5] = {1,2,3,4,5};
int y[5] = {6,7,8,9,0};
x = y; // Fails to compile
Run Code Online (Sandbox Code Playgroud)
但是当我在一个类中放入一个数组时,复制构造函数和赋值运算符工作(我会按预期说,但它不是我所期望的).
#include <iostream>
struct X
{
virtual ~X(){} // Just in case it was something to do with POD
// make sure its not a POD
int x[5];
};
int main()
{
X a;
a.x[0] = 0;
a.x[1] = 1;
a.x[2] = 2;
a.x[3] = 3;
a.x[4] = 4;
// Make a copy of a and test it
X b(a);
std::cout << a.x[0] << …Run Code Online (Sandbox Code Playgroud)