AOP-Chap15-Object Creation and Destruction

1 Object Construction

  • always called when you create an object
  • cannot be called directly (at any time) by the programmer but instead can only be called during object creation
  • constructor has no return type (not even void) and the same name as the class it is inside of
class BankAccount {
private:
	double balance;
public:
	BankAccount() {//构造器
  		balance = 0;
	}
	//other methods remain the same
};	
  • 构造器写在class外面也行
BankAccount::BankAccount() {
	balance = 0;
}

在这里插入图片描述
在这里插入图片描述

1.1 Overloading 重载

BankAccount::BankAccount() {
	balance = 0;
}
BankAccount::BankAccount(double initialBalance) {
	balance = initialBalance;
}	
  • default constructor
//C++编译器默认产生该构造器
class MyClass {
public:
	MyClass() {}
};
  • if you write any other constructor, the C++ compiler does not provide this constructor
  • write any constructors, the class is non-POD
  • not write a constructor and the compiler provides an implicit default constructor, the class is non-POD if that constructor turns out to be nontrivial(does something)
  • A class type that has a public default constructor—whether explicitly declared or automatically provided—is called a default constructible class
BankAccount myAccount(42.3); //pass 42.3 as initialBalance
//错误!!!!!
BankAccount x(); //interpreted as a function named x that takes no parameters and returns a BankAccount

1.2 Dynamic Allocation

  • 如果不创建local variable, 而是想要动态分配一个object
BankAccount * accountPtr = new BankAccount();
BankAccount * accountPtr = new BankAccount(initialBalance);
//必须是default constructor on each of them in ascending order of index
BankAccount * accountArray = new BankAccount[42]();//allocate space for an array
//class does not have a default constructor or want to initialize the elements of the array with some other constructor, need to create an array of pointers and then write a loop
BankAccount ** accountPointerArray = new BankAccount*[42]();
for (int i = 0; i < 42; i++) {
	accountPointerArray[i] = new BankAccount(initialBalances[i]);
}	

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.3 Types of Initialization

  • difference between
/*
value initialization
class with a default constructor is initialized by its default constructor
class without any constructor has every field value initialized
Non-class types are zero initialized
Arrays have their elements value initialized
*/
BankAccount * accountPtr = new BankAccount(); //parentheses

/*
default initialization
non-POD types are initialized by their default constructor
POD -> uninitialized
Arrays have their elements default initialized
*/
BankAccount * accountPtr = new BankAccount; //no parentheses
  • just always include a default constructor in your classes,则两者都用default constructor(有就是non-POD)初始化

1.4 Initializer Lists

  • initializer list is a list of initializations written by placing a colon after the close parenthesis of the constructor’s parameter list and writing a sequence of initializations before the open curly brace of the function’s body
BankAccount::BankAccount() : balance(0) {}
BankAccount::BankAccount(double initBal) : balance(initBal) {}

在这里插入图片描述
在这里插入图片描述

  • class has fields of a reference type, must initialize them in the initializer list不能用assign statement
  • const field must be initialized in the initializer list and may not be assigned to anywhere
  • order in which fields are initialized by the initializer list is the order in which they are declared in the class, not the order their initializers are written in the initializer list
class Something {
private:
	int x;
	int y;
	int z;
public:
	Something(int a, int b, int c) : z(c), y(b), x(a) {}
};//order of initialization would be x(a), y(b), z(c)		

在这里插入图片描述

在这里插入图片描述

  • x is the sum of z + y, neither of which have been initialized yet, so x gets initialized to some unknown value报错
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • a2被省略,使用默认的A()

1.5 What to Do

  • Make your classes default constructible --> Write a public default constructor in every class that you write
  • Use initializer lists to initialize your class’s fields
  • In the initializer list, explicitly initialize every field
  • Initialize the fields in the order they are declared
  • Use new and new[], not malloc

2 Object Destruction

  • destructor -->
    no return type, not even void;
    may not be overloaded;
    A class may only have one destructor, and it must take no parameters;
    receives an implicit this parameter;
    typically public
class BankAccount {
private:
	Transaction * transactionHistory; //array of transactions
	int numTransactions;
	double balance;
	void addTransaction(double amount, const char * message) {
		Transaction * temp = new Transaction[numTransactions+1]; 
		for (int i = 0; i < numTransactions; i++) {
  			temp[i] = transactionHistory[i];
		}
		temp[numTransactions].message = message;
		temp[numTransactions].amount = amount;
		gettimeofday(&temp[numTransactions].when, NULL);
		Transaction * old = transactionHistory;
		transactionHistory = temp;
		numTransactions++; 
		delete[] old;
	}
public:
	BankAccount() : transactionHistory(NULL), numTransactions(0), balance(0) {}
	~BankAccount() {
		delete[] transactionHistory;
	}
	void deposit(double amount) {
  		addTransaction(amount, "Deposit");
  		balance += amount;
	}
	double withdraw(double desiredAmount) { 
		if (desiredAmount <= balance) {
			addTransaction(-desiredAmount, "Withdraw"); 
			balance -= desiredAmount;
			return desiredAmount;
		}
		else {
			double actualAmount = balance;
			addTransaction(-actualAmount, "Withdraw (attempted too much)");
			balance = 0;
			return actualAmount;
		} 
	}
	double getBalance() const { 
		return balance;
	}
};			
  • delete and delete[] free the memory allocated by new and new[] respectively

2.1 When Are Destructors Invoked

  • deallocate memory for an array with delete[], the elements of the array have their destructor (if any) invoked in decreasing order of index—the opposite order from which they were constructed
  • local variables(and parameters) --> “box” is destroyed whenever they go out of scope
  • If the variable’s type is a class with a destructor (note: not a pointer to a class with a destructor, in which case, only the pointer is being destroyed, not the object) --> the destructor must be invoked before the box is destroyed
  • If multiple variables go out of scope at the same point --> their destructors are invoked in the opposite order from the order in which they were constructed
#include <cstdio>
#include <cstdlib>
class Example {
	int x;
public:
	Example(int i) : x(i) { 
		std::printf("Created example %d\n", x);
	}	
public:
	~Example() {
  		std::printf("Destroyed example %d\n", x);
  	}
};
int main(void) {
	Example e1(42);
	Example e2(99);
	for (int i = 0; i < 4; i++) {
 		Example eloop(i);
	}
return EXIT_SUCCESS;  		
}	
  • eloop goes out of scope at the close curly brace that ends the for loop, and another object by the same name is initialized the next time around the loop
Created example 42
Created example 99
Created example 0
Destroyed example 0
Created example 1
Destroyed example 1
Created example 2
Destroyed example 2
Created example 3
Destroyed example 3
Destroyed example 99
Destroyed example 42   

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 如果不自己declare一个destructor,编译器隐式提供一个
class MyClass {
public:
	~MyClass() {}
};	
  • trivial destructor --> automatically supplied destructor
  • nontrivial destructor --> explicitly write a destructor (even if it has nothing in it) --> non-POD type
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

3 Object Copying

  • Naïvely copying an object via parameter passing
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • Naïvely copying an object via assignment
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • Objects that are not POD cannot simply be copied from one location to another

3.1 Copy Constructor

  • Copying during initialization occurs when a new object is created as a copy of an old one
  • occurs when objects are passed to functions by value (as opposed to passing a reference or pointer)
  • when an object is returned from a function by value
  • explicitly when writes another object of the same type as the initializer for a newly declared object
class Polygon {
	Point * points;
	size_t numPoints;
public:
	Polygon(size_t n) : points(new Point[n]), numPoints(n) {}
	//copy constructor: makes a deep copy
	Polygon(const Polygon & rhs) : points(new Point[rhs.numPoints]), numPoints(rhs.numPoints) { 
		for (size_t i = 0; i < numPoints; i++) {
   			points[i] = rhs.points[i];
		}
	}
	~Polygon() {
		delete[] points; 
	}
};		
  • copy constructor is named the same as the class in which it resides
  • no return type (not even void)
  • takes a reference (generally a const reference) to its own type
  • 如果需要pass the argument as the value of the object,get it into copy constructor
  • 可以有multiple copy constructors: one that takes a const reference, and one that takes a non-const reference
  • 如果不显示地写copy constructor,C++ automatically provides one
class SomeClass {
	Type1 field1;
	Type2 field2;
	...
	Type3 field3;
public:
	//this is what the provided copy constructor would
	//look like if you did not write any copy constructor 
	SomeClass(const SomeClass & rhs) : field1(rhs.field1), field2(rhs.field2), ... fieldN(rhs.fieldN) {}
};		

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • automatically generated copy constructor will take a const reference as an argument if possible (i.e., if all fields have copy constructors which take const references), otherwise, it will have a non-const reference as an argument
  • automatically provided by the compiler --> trivial
  • user-defined copy constructors --> non-trivial

3.2 Assignment Operator

  • copy during assignment
  • change the value of an object that already exists (and is already initialized) to be a copy of another object
  • overload the assignment operator to specify how their objects should be copied during assignment
class Polygon {
	Point * points;
	size_t numPoints;
public:
	Polygon(size_t n) : points(new Point[n]), numPoints(n) {}
	//copy constructor: makes a deep copy
	Polygon(const Polygon & rhs) : points(new Point[rhs.numPoints]), numPoints(rhs.numPoints) { 
		for (size_t i = 0; i < numPoints; i++) {
     		points[i] = rhs.points[i];
  		}
  	}
  	Polygon & operator=(const Polygon & rhs) {
		if (this != &rhs) {
			Point * temp = new Point[rhs.numPoints];
			for (size_t i = 0; i < rhs.numPoints; i++) {
      			temp[i] = rhs.points[i];
    		}
			delete[] points;
			numPoints = rhs.numPoints; 
			points = temp;
			}
		return *this; 
	}
	~Polygon() { 
		delete[] points;
	}
};			
  • takes a constant reference to its own type
  • 和copy constructor有3个difference
    1. assignment operator returns a reference to this object
    2. checking if this!= &rhs --> if the object being assigned to is distinct from the object copied --> comparing pointers (i.e., we do this != &rhs), not values (i.e., do not do *this != &rhs)
    3. assignment operator must clean up the existing object before we assign the copied values to it
  • if the user does not write an assignment operator, one is automatically provided
class SomeClass {
	Type1 field1;
	Type2 field2;
	...
	TypeN fieldN;
public:
	//this is what the automatically provided assignment operator does
	SomeClass & operator=(const SomeClass & rhs) { 
	field1 = rhs.field1;
	field2 = rhs.field2;
	...
	fieldN = rhs.fieldN; 
	return *this;
	}
};		
  • automatically provided assignment operator does not check for self-assignment before copying the fields

3.3 Executing Code with Copying

  • 首先确定是使用copy constructor(initializing an object that you are newly creating)还是assignment operator(changing the values in an existing object)
  • 确定constructor/operator是不是trivial
    • automatically provided --> trivial --> 向C语言一样简单copy
    • non-trivial --> call it like a function
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述

3.4 Rule of Three

  • if write a destructor, copy constructor, or assignment operator in a class, must write all three of them

4 Unnamed Temporaries

  • unnamed temporaries — values that are created as the result of an expression but not given a name
  • 当unnamed temporaries是object,需要
MyClass(42);//create an unnamed object
/*
allocate space for an object of type MyClass in the current stack frame
“box” will not have any name
initialize it by passing 42 to its constructor
this argument of the constructor will be an arrow pointing at the unnamed box
object will then be immediately destroyed using destructor
*/
x = MyClass(42) + MyClass(17) * MyClass(3);
/*
creates five unnamed temporaries
temporaries are destroyed (in reverse order of their creation) at the end of the entire assignment expression — that is, after the result of the addition is assigned to x
*/

4.1 Parameter Passing

  • legal and constructs an unnamed temporary
  • copies that unnamed temporary object into the stack frame for someFunction, and then destroys the temporary after someFunction returns
someFunction(MyClass(42));
  • rather than constructing an unnamed temporary and copying it into someFunction’s frame, the compiler is allowed to create the object directly in someFunction’s frame to avoid the extra copy operation
  • object that it creates is still destroyed at the proper time
  • called function destroy everything except the parameters, and the caller destroy the parameters
  • 如下最好,用reference代替copy一个object
int someFunction(const MyClass & something) { ... }
  • create a “box” for the unnamed temporary and pass the address of that box as the pointer that is the reference
  • reference必须加const,non-const不能pass an unnamed temporary, as it is not an lvalue

4.2 Return Values

  • 正常情况:function (or operator) creates an object, and that object is explicitly copied to initialize the unnamed temporary using copy constructor(as the unnamed temporary is a newly created object), after which the local object inside the function would be destroyed
  • 但C++ allows the compiler to elide the copy, it arranges for the result to be directly initialized from within the function --> return value optimization

4.3 Implicit Conversions

int someFunction(const MyClass & something) { ... }
...
...
someFunction(MyClass(42));
  • can write the call to someFunction like this (even if someFunction is not overloaded to take an int):
someFunction(42);
  • The compiler is only allowed to apply this rule once per initialization. That is, if class A has a constructor that takes a B, and B has a constructor that takes a C, then we may not pass a C where an A is required and expect the compiler to make a temporary B from which it then can then make a temporary A
  • should declare all of your single-argument constructors except your copy constructors as explicit
class MyClass {
	//other stuff here...
public:
	explicit MyClass(int x) : someField(x) { ... }
	MyClass(const MyClass & rhs) : someField(rhs.someField) { ... }
	//other stuff here...
};	
  • copy constructor should never be declared as explicit
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值