问题描述
我们来看一个简单的例子:pre $ $ $ $ $ struct struct some_struct {
std :: string str;
int a,b,c;
}
some_struct abc,abc_copy;
abc.str =一些文字;
abc.a = 1;
abc.b = 2;
abc.c = 3;
abc_copy = abc;
然后abc_copy是 abc的确切副本
.. 没有定义 =运算符怎么可能?
如果你没有定义这四种方法(在C + +中有六种方法) +11)编译器会为你生成它们:
$ b $ ul
如果你想知道为什么?保持与C的向后兼容性(因为C结构可以使用=和在声明中复制)。但它也使编写简单的类更容易。有人会说,由于浅拷贝问题,它增加了问题。我反对的观点是你不应该拥有一个拥有RAW指针的类。
默认构造函数(如果没有定义其他构造函数)
析构函数(如果未定义析构函数)
复制构造函数(如果没有定义复制构造函数)
赋值运算符
移动构造函数(如果没有移动构造函数定义)
移动赋值运算符
如果您定义了一个像这样的类:
struct some_struct:public some_base
{
std :: string str1;
int a;
float b;
char * c;
std :: string str2;
};
编译器将构建的是:
struct some_struct:public some_base
{
std :: string str1;
int a;
float b;
char * c;
std :: string str2;
//从概念上讲,默认构造函数有两种不同的版本:
//一个用于初始化另一个用于零初始化
//使用的版本取决于该对象被声明。
// some_struct * a = new some_struct; // value-initialized
// some_struct * b = new some_struct(); //零初始化
// some_struct c; // value-initialized
// some_struct d = some_struct(); //零初始化
//注意:仅仅因为概念上有两个构造函数并不意味着
//实际上有两个构造函数。
// value初始化版本
some_struct()
:some_base()// value-initialize base(if compiler generated)
,str1()//有一个正常的构造函数,所以只需将它称为
// PODS未初始化
,str2()
{}
//初始化版本
some_struct ()
:some_base()//零初始化base(如果编译器生成)
,str1()//有一个正常的构造函数,所以就调用它。
,a(0)
,b(0)
,c(0)// 0是NULL
,str2()
//将所有填充初始化为(复制)
,str1(copy.str1)
,a(复制)
,
$ .a)
,b(copy.b)
,c(copy.c)
,str2(copy.str2)
{}
some_struct&安培; operator =(some_struct const& copy)
{
some_base :: operator =(copy);
str1 = copy.str1;
a = copy.a;
b = copy.b;
c = copy.c;
str2 = copy.str2;
return * this;
}
〜some_struct()
{}
//注意以下代码是伪代码
//同时注意在用户代码后会发生成员破坏。
//在编译器生成的版本中,用户代码为空
:〜str2()
// POD没有析构函数
,〜str1()
,〜some_base();
//这里是析构函数的结尾。
//在C ++ 11中,我们还有Move构造函数和移动赋值。
some_struct(some_struct&& copy)
// ^^^^注意double&&
:some_base(std :: move(copy))
,str1(std :: move(copy.str1))
,a(std :: move(copy.a))
,b(std :: move(copy.b))
,c(std :: move(copy.c))
,str2(std :: move(copy.str2))
{}
some_struct& operator =(some_struct& amp; copy)
// ^^^^注意double&&
{
some_base :: operator =(std :: move(copy));
str1 = std :: move(copy.str1);
a = std :: move(copy.a);
b = std :: move(copy.b);
c = std :: move(copy.c);
str2 = std :: move(copy.str2);
return * this;
}
};
Let's look at a simple example:
struct some_struct {
std::string str;
int a, b, c;
}
some_struct abc, abc_copy;
abc.str = "some text";
abc.a = 1;
abc.b = 2;
abc.c = 3;
abc_copy = abc;
Then abc_copy is an exact copy of abc
.. how is it possible without defining the = operator?
(This took me by surprise when working on some code..)
If you do not define these four methods (six in C++11) the compiler will generate them for you:
- Default Constructor
- Copy Constructor
- Assignment Operator
- Destructor
- Move Constructor (C++11)
- Move Assignment (C++11)
If you want to know why?
It is to maintain backward compatibility with C (because C structs are copyable using = and in declaration). But it also makes writing simple classes easier. Some would argue that it adds problems because of the "shallow copy problem". My argument against that is that you should not have a class with owned RAW pointers in it. By using the appropriate smart pointers that problem goes away.
Default Constructor (If no other constructors are defined)
Destructor (If no destructor defined)
Copy Constructor (If no copy constructor is defined)
Assignment Operator
Move Constructor (If no move constructor is defined)
Move Assignment Operator
If you define a class like this:
struct some_struct: public some_base
{
std::string str1;
int a;
float b;
char* c;
std::string str2;
};
What the compiler will build is:
struct some_struct: public some_base
{
std::string str1;
int a;
float b;
char* c;
std::string str2;
// Conceptually two different versions of the default constructor are built
// One is for value-initialization the other for zero-initialization
// The one used depends on how the object is declared.
// some_struct* a = new some_struct; // value-initialized
// some_struct* b = new some_struct(); // zero-initialized
// some_struct c; // value-initialized
// some_struct d = some_struct(); // zero-initialized
// Note: Just because there are conceptually two constructors does not mean
// there are actually two built.
// value-initialize version
some_struct()
: some_base() // value-initialize base (if compiler generated)
, str1() // has a normal constructor so just call it
// PODS not initialized
, str2()
{}
// zero-initialize version
some_struct()
: some_base() // zero-initialize base (if compiler generated)
, str1() // has a normal constructor so just call it.
, a(0)
, b(0)
, c(0) // 0 is NULL
, str2()
// Initialize all padding to zero
{}
some_struct(some_struct const& copy)
: some_base(copy)
, str1(copy.str1)
, a(copy.a)
, b(copy.b)
, c(copy.c)
, str2(copy.str2)
{}
some_struct& operator=(some_struct const& copy)
{
some_base::operator=(copy);
str1 = copy.str1;
a = copy.a;
b = copy.b;
c = copy.c;
str2 = copy.str2;
return *this;
}
~some_struct()
{}
// Note the below is pseudo code
// Also note member destruction happens after user code.
// In the compiler generated version the user code is empty
: ~str2()
// PODs don't have destructor
, ~str1()
, ~some_base();
// End of destructor here.
// In C++11 we also have Move constructor and move assignment.
some_struct(some_struct&& copy)
// ^^^^ Notice the double &&
: some_base(std::move(copy))
, str1(std::move(copy.str1))
, a(std::move(copy.a))
, b(std::move(copy.b))
, c(std::move(copy.c))
, str2(std::move(copy.str2))
{}
some_struct& operator=(some_struct&& copy)
// ^^^^ Notice the double &&
{
some_base::operator=(std::move(copy));
str1 = std::move(copy.str1);
a = std::move(copy.a);
b = std::move(copy.b);
c = std::move(copy.c);
str2 = std::move(copy.str2);
return *this;
}
};
这篇关于为什么=操作符在结构上工作而没有定义?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!