• Non ci sono risultati.

Prof. Marco Bertinimarco.bertini@unifi.ithttp://www.micc.unifi.it/bertini/ Programmazione

N/A
N/A
Protected

Academic year: 2021

Condividi "Prof. Marco Bertinimarco.bertini@unifi.ithttp://www.micc.unifi.it/bertini/ Programmazione"

Copied!
18
0
0

Testo completo

(1)

Programmazione

Prof. Marco Bertini marco.bertini@unifi.it

http://www.micc.unifi.it/bertini/

(2)

Deep vs. shallow copy

(3)

Methods created by the compiler

We have seen that the compiler creates for each class a default constructor and

destructor…

… but it creates also default copy

constructor and assignment operator, to

create a new object cloning another one or copying its attributes.

C++11 compiler may create other

methods, not discussed in this lecture.

(4)

Copy methods

C++ treats variables of user-defined types

with value semantics. This means that objects are implicitly copied in various contexts.

The copy constructor creates a fresh object based on the state of an existing object.

The assignment operator copies the state of a source object onto an existing target object, thus it has to work a bit more to deal with the already existing target.

(5)

The compiler

According to the C++ standard:

The compiler will implement copy constructor and assignment operator if they are used but not provided by the programmer (implicit definition)

The implicitly-defined copy constructor for a

non-union class X performs a memberwise copy of its sub-objects.

The implicitly-defined copy assignment operator for a non-union class X performs memberwise copy assignment of its subobjects.

(6)

Shallow copy

The implicit methods copy the content of the attributes of the class, i.e. they perform a bit- by-bit copy of their content (shallow copy).

Is this enough to get a working copy of our object ?

(7)

Shallow copy example

class GameCharacter { public:


GameCharacter(std::string& name, 


int hp) : name(name), hp(hp) 
 { }


private:


std::string name;


int hp;

};

// Implicit methods created by the
 // compiler. The default constructor
 // is not created because of the


// constructor provided by us.

// 1. copy constructor


GameCharacter(GameCharacter& that) : 
 name(that.name), hp(that.hp) { } // 2. copy assignment operator


GameCharacter& operator=(GameCharacter&


that) {
 name = that.name;


hp = that.hp;


return *this;


}

// 3. destructor


~person() {
 }

(8)

Shallow copy example

class GameCharacter { public:


GameCharacter(std::string& name, 


int hp) : name(name), hp(hp) 
 { }


private:


std::string name;


int hp;

};

// Implicit methods created by the
 // compiler. The default constructor
 // is not created because of the


// constructor provided by us.

// 1. copy constructor


GameCharacter(GameCharacter& that) : 
 name(that.name), hp(that.hp) { } // 2. copy assignment operator


GameCharacter& operator=(GameCharacter&


that) {
 name = that.name;


hp = that.hp;


return *this;


}

// 3. destructor


~person() {
 }

Memberwise copy.

The attributes are 
 copied bit-by-bit

(9)

Shallow copy example

class GameCharacter { public:


GameCharacter(std::string& name, 


int hp) : name(name), hp(hp) 
 { }


private:


std::string name;


int hp;

};

// Implicit methods created by the
 // compiler. The default constructor
 // is not created because of the


// constructor provided by us.

// 1. copy constructor


GameCharacter(GameCharacter& that) : 
 name(that.name), hp(that.hp) { } // 2. copy assignment operator


GameCharacter& operator=(GameCharacter&


that) {
 name = that.name;


hp = that.hp;


return *this;


}

// 3. destructor


~person() {
 }

Memberwise copy.

The attributes are 
 copied bit-by-bit

Typically these are “constant” arguments.


We’ll see what is const in a future lecture.

(10)

Deep copy

If an attribute of the class is a pointer, e.g. to an array the bit-by-bit copy is not enough,

since it results in copying the address and not the objects that are pinted.

We need a deep copy that copies all the objects pointed, or we risk that the

destruction of a copied object destroys the original.

(11)

Deep copy

If an attribute of the class is a pointer, e.g. to an array the bit-by-bit copy is not enough,

since it results in copying the address and not the objects that are pinted.

We need a deep copy that copies all the objects pointed, or we risk that the

destruction of a copied object destroys the original.

Think of a bad photocopier that creates magical copies that once destroyed cause automatic destruction of the original…

(12)

Shallow copy problem

class GameCharacter {
 public:


// ...


~GameCharacter() {


delete[] inventory;


}

private:


std::string name;


int hp;


Potion* inventory;

};

(13)

Shallow copy problem

class GameCharacter {
 public:


// ...


~GameCharacter() {


delete[] inventory;


}

private:


std::string name;


int hp;


Potion* inventory;

};

Elrond

12

0x954FFA

Potion object 1 Potion object 2 Potion object n

std::string name

int hp

Potion* inventory

GameCharacter hero

Original object

Elrond

12

0x954FFA std::string name

int hp

Potion* inventory

GameCharacter copied_hero Shallow copy object

If the shallow copy object copied_hero gets destructed then also the original object hero loses

its inventory

(14)

Shallow copy problem

class GameCharacter {
 public:


// ...


~GameCharacter() {


delete[] inventory;


}

private:


std::string name;


int hp;


Potion* inventory;

};

Elrond

12

0x954FFA

Potion object 1 Potion object 2 Potion object n

std::string name

int hp

Potion* inventory

GameCharacter hero

Original object

Elrond

12

0x954FFA std::string name

int hp

Potion* inventory

GameCharacter copied_hero Shallow copy object

If the shallow copy object copied_hero gets destructed then also the original object hero loses

its inventory

A deep copied object causes no issue to the source:

it has its own copy of the resources.

Elrond

12

0x954FFA

Potion object 1 Potion object 2 Potion object n

std::string name

int hp

Potion* inventory

GameCharacter hero

Original object

Elrond

12

0x32BA84 std::string name

int hp

Potion* inventory

GameCharacter copied_hero Deep copy object

Copied Potion object

1 Copied Potion object

2 Copied Potion object

n

(15)

“Rule of three”

When our class manages a resource, i.e. when an object of the class is responsible for that

resource, then we need to declare explicit

methods for copying and creating objects from other objects. 


Typically the resource is acquired in the

constructor (or passed into the constructor) and released in the destructor.

Implement copy constructor, destructor and assignment operation.

(16)

How to create the methods ?

Both copy constructor and assignment operator receive a reference to the original (source) object.

Actually a const reference…

The methods share a lot of code. Think about factorizing it in an helper method.

The destructor should release the resource

The operator returns a reference, to all multiple

assignments. The operator must handle the existing resources of the target object and avoid self

assignment.

(17)

Reading material

L.J. Aguilar, “Fondamenti di programmazione in C++. Algoritmi, strutture dati e oggetti” - cap.

12, pag. 381-383

D.S. Malik, “Programmazione in C++” - cap. 10, pag. 510-512

Thinking in C++, 2nd ed. Volume 1, cap. 11, pag.

479-497

(18)

Credits

These slides are based on the material of:

D.S. Malik, “Programmazione in C++”

Riferimenti

Documenti correlati

• The most powerful use of const is its application to function declarations: we can refer to function return value, function parameters and (for member functions) to the

• When working with classes that have a pointer to Abstract Base Classes we can not use directly the copy constructor of the ABC…. • use the “virtual” constructor technique

• note that all parameter types need not satisfy all requirements implied by the full template definition - since only some member functions may be actually needed and called for

iterator erase(iterator i, iterator j) remove the range [i,j), return the iterator pointing to the next element if it exists; end() otherwise
.

• during the stack unwinding resulting from the processing of the exception are called the destructors of local objects, and one may trigger another exception.. use

If the container of smart pointers is emptied, the three objects in the ring will get automatically deleted because no other smart pointers are pointing to them; like raw pointers,

another class (Adaptee) to a client, using the expected interface described in an abstract class (Target). • Uses multiple inheritance,

• Need to update multiple objects when the state of one object changes (one- to-many dependency)..