!!!Chapter 13 Copy Control
来源:互联网 发布:知其所以然论坛网址 编辑:程序博客网 时间:2024/06/14 06:19
When we define a new type, we specify what happens when objects of that type are copied, assigned, and destroyed. We do so by defining special members: the copy constructor, the assignment operator and the destructor.
If we do no explicitly define the copy constructor or the assignment operator, the compiler will define them for us.
Collectively, the copy constructor, assignment operator, and destructor are referred to as copy control. The compiler automatically implements these operations, but the class may define its own versions.
13.1 The Copy Constructor
The constructor that takes a single parameter that is a (usually const) reference to an object of the class type itself is called the copy constructor.
The copy constructor is used to
- Explicitly or implicitly initialize one object from another of the same type
- Copy an object to pass it as an argument to a function
- Copy an object to return it from a function
- Initialize the elements in a sequential container
- Initialize elements in an array from a list of element initializers
Forms of Object Definition
C++ supports two forms of initialization: direct and copy. Copy-initialization uses the = symbol, and direct-initialization places the initializer in parentheses.
For class, direct-initialization directly invokes the constructor matched by the arguments. Copy-initialization always involves the copy constructor.Copy-initialization first uses the indicated constructor to create a temporary object. It then uses the copy constructor to copy that temporary into the one we are creating:
string null_book = "9-999-9999"; //copystring dots(10, ','); //directstring empty_copy = string(); //copystring empty_direct; //direct
For class type objects, copy-initialization can be used only when specifying a single argument or when we explicitly build a temporary object to copy.
Usually the difference between direct- or copy-initialization is at most a matter of low-level optimization. However, for types that do not support copying, or when using a constructor that isnonexplicit the distinction can be essential: P 477
Parameters and Return Values
When the parameter/return value is a nonreference type, it is copied.
Initializing Container Elements
The copy constructor is used to initialize the elements in a sequential container. E.G.
//default string constructor and five string copy constructors invoked.vector<string> svec(5);
Constructors and Array Elements
If we provide no element initializers for an array of class type, then the default constructor is used to initialize each element. But if we provide explicit element initializers using the normal brace-enclosed array initialization list, then each element is initialized using copy-initialization. P 479.
13.1.1 The Synthesized Copy Constructor
The compiler will synthesize copy constructor for us, if we do not define the copy constructor.
The behavior of the synthesized copy constructor is memberwise initialize the new object as a copy of the original object.
memberwise means taking each nonstatic member in turn, the compiler copies the member from the existing object into the one being created:
- For built-in type, the value of members are copied directly
- For members of class type, it will use copy constructor for that class
- For array members, copy constructor will copy the array by copying each element. (normally, we cannot copy an array)
13.1.2 Defining Our Own Copy Constructor
The copy constructor is defined like any other constructor: it has the same name as the name of the class, it has no return value, it may(should) use a constructor initializer to initialize the members of the newly created object, and it may do any other necessary work inside a function body.
class Foo {public: Foo(); // default constructor Foo (const Foo&); // copy constructor};Because the constructor is used(implicitly) to pass and return objects to and from functions, it usually should not be made explicit.
For classes that contain only members of class type or built-in type, we can rely on synthesized copy constructor.
For classes that have a data member of pointer or do bookkeeping, we may need to define our own copy constructor.
13.1.3 Preventing Copies
To prevent copies, we can define the copy constructor as private. In this way, only friends and members of the class can make copies.
To prevent copies within friends and members, we can do so by declaring a (private) copy constructor but not defining it.
Objects of classes that do not allow copies may be passed to(return from) a function only as a reference. They also may not be used as elements in a container.
The default constructor is synthesized only if there are no other constructors. If the copy constructor is defined, then the default constructor must be defined as well.
13.2 The Assignment Operator
As with the copy constructor, the compiler synthesizes an assignment operator if the class does not define its own.
Introducing Overloaded Assignment
Overloaded operators are functions that have the name operator followed by the symbol for the operator being defined. E.G. operator=
An operator function also has a return type and a parameter list. The parameter list must have the same number of parameters as the operator has operands.
Most operators may be defined as member or nonmember functions. When an operator is a member function, its first operand is implicitly bound to thethispointer.
Assignment function should return a reference to its left-hand operand.
class Sales_item{public: Sales_item& operator= (const Sales_item &); //declaration so need a ;};
The Synthesized Assignment Operator
The synthesized assignment operator operates similarly to the synthesized copy constructor. It performsmemberwise assignment.
Sales_item&Sales_item::operator= (const Sales_item &rhs){ isbn = rhs.isbn; units_sold = rhs.units_sold; revenue = rhs.revenue; return *this;}The operator returns *this, which is a reference to the left-hand object. (有返回值,所以可以连等: a=b=c)
Copy and Assign Usually Go Together
Classes that can use the synthesized copy constructor usually can use the synthesized assignment operator as well.
If a class needs a copy constructor, it will also need an assignment operator.
13.3 The Destructor
The destructor serves as the complement to the constructors of the class.
When a Destructor Is Called
The destructor is called automatically whenever an object of its class is destroyed:
// p points to default constructed objectSales_item *p = new Sales_item;{ //new scope Sales_item item(*p); //copy constructor copies *p into item delete p; //destructor called on object pointed to by p} //exit local scope; destructor called on itemVariable such as item are destroyed automatically when they go out of scope. Hence, the destructor on item is run when the close curly is encountered.
An object that is dynamically allocated is destroyed only when a pointer pointing to the object is deleted.
The destructor is not run when a reference or a pointer to an object goes out of scope. The destructor is run only when a pointer to a dynamically allocated object is deleted or when an actual object goes out of scope.
When to Write an Explicit Destructor
Rule of Three: if a class needs a destructor, it will also need the assignment operator and a copy constructor.
The Synthesized Destructor
Unlike the copy constructor or assignment operator, the compiler always synthesizes a destructor for us.The synthesized destructor destroys nonstatic member in reverse order.
How to Write a Destructor
Classes that do allocate resources usually need to define a destructor to free those resources.
The destructor is a member function with the name of the class prefixed by a tilde (~). It has no return value and takes no parameters. Since it has no parameter, it cannot be overloaded.
Even if we write our own destructor, the synthesized destructor is still run.
class Sales_item {public: ~Sales_item() {} //define a destructor};
13.5 Managing Pointer Members
classes that contain pointers require careful attention to copy control. The reason they must do so is that copying a pointer copies only the address in the pointer. Copying a pointer does not copy the object to which the pointer points.
Through different copy-control strategies we can implement different behavior for pointer members:
1. The pointer member can be given normal pointerlike behavior: Such classes will have all the pitfalls of pointers but will require no special copy control.
2. The class can implement so-called "smart pointer" behavior. The object to which the pointer points is shared, but the class prevents dangling pointers.
3. The class can be given valuelike behavior. The object to which the pointer points will be unique to and managed separately by each class object.
Normal pointer member P 493
13.5.1 Defining Smart Pointer Classes P 495
A smart pointer behaves like an ordinary pointer except that it adds functionality.
Introducing Use Counts
The use count keeps track of how many objects of the class share the same pointer. When the use count goes to zero, then the object is deleted.
A use count is sometimes also referred to as a reference count.
The counter cannot go directly into the HasPtr object. P 495
The Use-Count Class
// private class for use by HasPtr onlyclass U_Ptr { friend class HasPtr; int *ip; size_t use; U_Ptr(int *p) : ip(p), use(1) {} ~U_Ptr() {delete ip;}};
Using the Use-Counted Class
class HasPtr {public: HasPtr(int *p, int i) : ptr(new U_Ptr(p)), val(i) {} HasPtr(const HasPtr &orig) : ptr(orig.ptr), val(orig.val) {++ptr->use;} HasPtr& operator=(const HasPtr&); ~HasPtr() { if (--ptr->use==0) delete ptr; }private: U_Ptr *ptr; int val;};
Assignment and Use Counts
HasPtr& HasPtr::operator=(const HasPtr &rhs){ ++rhs.ptr->use; if(--ptr->use == 0) //anyway, minus one delete ptr; ptr = rhs.ptr; val = rhs.val; return *this;}We do increment before decrement, so that we can do self-assignment! (Otherwise, the object may be destroyed!)
13.5.2 Defining Valuelike Classes
When we copy a valuelike object, we get a new, distinct copy:
class HasPtr {public: HasPtr (const int &p, int i) : ptr(new int(p)), val(i) {} HasPtr (const HasPtr &orig) : ptr(new int (*orig.ptr)), val(orig.val) {} HasPtr& operator=(const HasPtr &); ~HasPtr() {delete ptr;}private: int *ptr; int val;};
The copy constructor will allocates a new int object and initialize that object to hold the same value as the object of which it is a copy
The assignment operator doesn't need to allocate a new object. It just has to remember to assign a new value to the object to which its int pointer points:
HasPtr & HasPtr::operator=(const HasPtr &rhs){ *ptr=*rhs.ptr; val=rhs.val; return *this;}The assignment operator must be correct even if we're assigning an object to itself.
- Chapter 13 Copy Control
- !!!Chapter 13 Copy Control
- Chapter.13 Copy Constructor
- 13-Copy Control
- Chapter 4 - Flow Control
- Chapter 9 Child Window Control
- Chapter 16 Control Unit Operation
- Chapter 17 Micro-Programmed Control
- 复制控制(copy control)
- C++11: deleted copy control
- 13.4. A Copy-Control Example
- Chapter 8 Exceptional Control Flow -- Nonlocal Jumps
- Chapter 06–Maintaining the Control File
- CHAPTER 24 VIRTUAL-MACHINE CONTROL STRUCTURES
- !!!Chapter 4 The Medium Access Control Sublayer
- VOFM、Copy Control与合并开票
- 13.2. Copy Control and Resource Management
- Chapter 3– Control Flow of TCPL (Part 9)
- AndEngine 物理世界引擎 JNI 引入
- ImageView属性详解
- Windows文件操作的笔记和关键,MMClassify V2.0
- codeforces上解题感受
- Windows 8实例教程系列 - 开篇
- !!!Chapter 13 Copy Control
- UVa 11559 - Event Planning
- UVa 146 - ID Codes
- Eclipse自动部署项目到Tomcat的webapps下的有效方法
- 后台播放音乐,防止iphone进入休眠,超详细教程(可制作音乐闹钟)
- UVa 11340 - Newspaper
- UVa11799 - Horror Dash
- UVa 579 - ClockHands
- UVa 11462 - Age Sort