350 likes | 468 Vues
This resource explores key concepts in C++ object management, focusing on constructors, including copy constructors, and the initialization processes of objects and members. It discusses the differences between initialization and assignment, the role of compiler-generated constructors, deep vs. shallow copies, and proper management of dynamic memory. Through practical examples, the document illustrates common pitfalls in object handling and offers insights into best practices for developing robust C++ applications.
E N D
The Rest of the Story Object Management
Object ManagementThe Rest of the Story • Constructors • Compiler-generated • The Initializer List • Copy Constructors • Single-arg (conversion ctors) • The Assignment Operator CS 3370 - C++ Software Development
Constructors • Execute after an object’s memory is allocated • Used to initialize an object’s memory • Which constructor executes depends on arguments passed • Run after sub-objects are initialized • Base classes and sub-objects initialize first • Example: initMembers.cpp CS 3370 - C++ Software Development
Initializing Member ObjectsDefault Behavior • Member objects are default-initialized • class types run the default constructor • built-in types are not initialized by default • See initInt.cpp, defaultinit.cpp • “Zero Initialization”: • Occurs with an explicit call to a default ctor • Even with built-ins: int x = int( ); // 0 • See defaultinit2.cpp CS 3370 - C++ Software Development
The Initializer List • By-passes default initialization • The only way to initialize const and reference members • It is inefficient and poor practice to initialize member objects in the body of the containing constructor • Built-in types are okay, though • Examples: badInit.cpp, goodInit.cpp, constMem.cpp CS 3370 - C++ Software Development
A Simple String ClassManages a char buffer #include <cstring> #include <iostream> class String { char* data; public: String(const char* s = "") { data = new char[std::strlen(s) + 1]; std::strcpy(data,s); } ~String() {delete [] data;} int size() const {return std::strlen(data);} char getAt(int pos) const {return data[pos];} void setAt(int pos, char c) const {data[pos] = c;} void display() { std::cout << data << '\n'; } }; CS 3370 - C++ Software Development
Using class String int main() { String s = "hello"; // same as String s("hello"); for (int i = 0; i < s.size(); ++i) cout << "s[" << i << "] == " << s.getAt(i) << std::endl; String empty; std::cout << '"'; empty.display(); std::cout << "\"\n"; } /* Output: s[0] == h s[1] == e s[2] == l s[3] == l s[4] == o "" */ CS 3370 - C++ Software Development
Strange Behavior int main() { String s = "hello"; String t = s; // same as String t(s); t.setAt(0,'j'); s.display(); } /* Output: jello a.out(4603) malloc: *** error for object 0x100100080: pointer being freed was not allocated */ CS 3370 - C++ Software Development
Initialization vs. Assignment • Initialization occurs only once, right after an object is created • always by some constructor • Assignment occurs only after an object has been initialized • via operator= • Which constructor executed in the previous slide? CS 3370 - C++ Software Development
The Copy Constructor • Initializes a new object as a copy of an existing object • of the same type or of some convertible type • Has signature T::T(const T&) • or T::T(T&) // not recommended • Copies each member across • using their own copy constructors, recursively • Generated by the compiler • But you can override it (and sometimes should) CS 3370 - C++ Software Development
Compiler-generated Copy Ctor String(const String& s) : data(s.data) {} // Identical here to: String(const String& s) { data = s.data; } (because pointers are not objects, and hence are not default-initialized.) CS 3370 - C++ Software Development
Shallow Copy s::data hello\0 t::data CS 3370 - C++ Software Development
Problems with Shallow Copy • If you have a pointer as a data member, a shallow copy is probably not what you want • Multiple pointers point to the same memory • If you de-allocate the data member in one object, you have created a likely fatal situation in the other (double delete) CS 3370 - C++ Software Development
Deep Copy • Classes with pointer members representing a dynamically allocated resource should offer a deep copy: • Allocate new heap space • Copy data to new target CS 3370 - C++ Software Development
A “Deep Copy” Copy Constructor String(const String& s) { data = new char[strlen(s.data)+1]; strcpy(data, s.data); } CS 3370 - C++ Software Development
Passing Objects by Value • Rarely done for non-built-in types • Objects are often returned by value, though • New values are often created • A copy is made • Therefore, a constructor executes • But which constructor? CS 3370 - C++ Software Development
Which Constructor? • Not always the copy constructor • Depends on the argument(s) • via overload resolution • As simple as that! • Example: trace.cpp CS 3370 - C++ Software Development
More Strange BehaviorAfter coding the Copy Constructor • Why does changing t affect s below? int main() { String s = "hello"; // same as String s("hello"); String t; t = s; t.setAt(0, 'j'); s.display(); } /* Output: jello a.out(4767) malloc: *** error for object 0x100100080: pointer being freed was not allocated */ CS 3370 - C++ Software Development
Object Assignment • Uses operator= • must be a member function • Generated by the compiler • assigns each data member individually • does a shallow copy • You can override it • and sometimes should, just like the copy constructor CS 3370 - C++ Software Development
Compiler-generated Assignment String& String::operator=(const String& rhs) { data = rhs.data; return *this; } s hello\0 t CS 3370 - C++ Software Development
What should String::operator=Do? • Allocate new heap space • Copy characters to target • Delete the old heap space • Return *this • Avoid unnecessary self-assignment • An optional but encouraged optimization • And watch the order you do things in! CS 3370 - C++ Software Development
Correct Assignment String& String::operator=(const String& s) { if (&s != this) // avoid self-copy { char* new_data = new char[strlen(s.data)+1]; strcpy(new_data, s.data); // copy delete [] data; // delete old data = new_data; // store new } return *this; // for full ass’t. semantics } CS 3370 - C++ Software Development
Prohibiting Copy and Assignment • A must for large objects (streams, etc.) • Make the copy constructor and assignment operator private • Will cause a compile error if client code tries to copy or assign • Only declare them • Define no function bodies • Will cause a link error if member functions try to copy or assign CS 3370 - C++ Software Development
Standard Conversions • Implicit promotion of numeric types • Widening of: • char -> short -> int -> long -> long long • Conversion from integer to floating-point • Needed in mixed-mode expressions (x + i) and in passing parameters • Function prototypes initiate the conversion for parms CS 3370 - C++ Software Development
Implicit Conversions to Class Type • You can allow conversions to and from any class type from or to any other type • Convert to a class type via a single-arg constructor • aka “conversion constructor” • Convert from a class type via a conversion operator • a special type of member function • You can turn off implicit conversions • With a special keyword (explicit) CS 3370 - C++ Software Development
Limitations • Sometimes multiple conversions occur invisibly in sequence in a single expression • Only one class type (i.e., non-primitive) is allowed inside a sequence of conversions • Example • convert.cpp • convert2.cpp CS 3370 - C++ Software Development
Turning off Implicit Conversions • explicit keyword • Example • convert3.cpp CS 3370 - C++ Software Development
Object Management Summary • Copy Constructor • the compiler generates a shallow one if you don’t define it • All Other Constructors • if you don’t provide any constructors at all, the compiler generates a default constructor (which default-constructs each member) • Single-arg constructors are conversion constructors • Assignment Operator • the compiler generates a shallow one if you don’t define it • Destructor • the compiler generates an empty one if you don’t define it • Members with destructors are destructed automatically anyway CS 3370 - C++ Software Development
const Correctness of Objects • const is your friend • It prevents modification errors by enforcing "read-only-ness" • const objects can only call constmember functions • all objects can call const member functions! • constmember functions receive the following this pointer: • const T * const this • Non-const member functions receive the following this pointer: • T * const this CS 3370 - C++ Software Development
const and mutable • const member functions cannot change fields: • “x = 2” “this->x = 2” // error in a const fn • Unless they’re mutable • “x = 2” “const_cast<T*>(this)->x = 2” • See mutable.cpp • Remember: const is a user-view thing CS 3370 - C++ Software Development
const-ness and Constructors • Objects don’t exist until they are fully initialized by a constructor • Constructors do not receive a this pointer • This if OK: you have to modify things during initialization! • So you don’t declare constructors const • Nor do they return anything CS 3370 - C++ Software Development
Overloading const • Consider front, back, and at in class Deque • They are non-const functions • They can’t be applied to a const Deque object • You can overload on const • So you can define overloaded const versions • See deque2.cpp and deque3.cpp • However, there is a problem with the return by reference! • Look at the return types of the const versions CS 3370 - C++ Software Development
const and Reference Returns • A const member function should never return a non-const reference • Remember, it’s a user-view thing • You are responsible to enforce this! • Always provide two overloads: • T& f( ); • const T& f() const; • Classical example: the indexing operator (same as at( )) • T& operator[](int pos); • const T& operator=(int pos) const; • See deque4.cpp CS 3370 - C++ Software Development
Initializing Static Data Members • Only the declaration goes in the class definition • Usually in a .h file • The definition of the member must occur at global scope • In a .cpp file • Defines space for the member in the data segment • (There is no “class object” in C++ like in other OO languages) CS 3370 - C++ Software Development
Defining a Static Pool ObjectFor Program 2 • In MyObject.h:class MyObject {static Pool pool;…}; • In MyObject.cpp:Pool MyObject::pool(…); CS 3370 - C++ Software Development