SlideShare a Scribd company logo
1 of 23
Download to read offline
1
Nico Ludwig (@ersatzteilchen)
(4) C++ Abstractions
2
TOC
● (4) C++ Abstractions
– The STL Type std::string
– C++ References and Const References
– More on RAII:
● Copy Constructors
● Temporary and Anonymous Objects
●
Type Conversion
– Const-ness in C++
●
Const Member Functions
●
Const Correctness
● Mutable Fields
● Sources:
– Bjarne Stroustrup, The C++ Programming Language
– John Lakos, Large-Scale C++ Software Design
3
C-Strings revisited
● In the last lectures we talked about the encapsulation of concepts and RAII.
– Now it's time to make use of RAII to make our programming tasks easier.
● E.g. we should apply RAII to encapsulate c-strings, thus enhancing:
– creation,
– assignment,
– copying and
– operations on c-strings
– by encapsulating the tedious memory management around c-strings.
● The good news: we don't have to create a new UDT, we can use STL-strings!
– STL-strings are represented by the C++ standard type std::string.
– The type std::string is defined in <string>.
– std::string provides important RAII features that make using std::string intuitive.
● Also the ugly 0-termination is to be encapsulated.
● The type std::string is a very good example of
encapsulation. The design of std::string makes
working with strings very comfortable, safe and
productive, esp. because RAII has been
implemented in std::string.
● Many different libraries implemented "their"
string types different from std::string (mutable
string types, immutable string types, reference
counted string types etc.), but we'll only use
const char* or std::string in this course.
4
The UDT std::string
● To use STL-strings we have to include <string> and keep on going with std::string:
● The type std::string can be used like a fundamental type, e.g. as return/parameter type:
● Hooray! - A simple-to-use string type in C++! But there is a performance problem:
– Due to RAII, std::strings are copied when passed to and returned from functions.
– It means that the encapsulated c-strings (char arrays) are allocated and freed multiply.
●
This is, e.g., done by ctors and dtors which manage RAII.
– Can we improve this situation?
std::string name = "Lola"; // Creation
std::string otherName = name; // Assignment/Copying
std::string subString = name.substr(2, 2); // Substring: a member function of std::string (result: "la")
// The memory of the used strings will be managed (e.g. also freed) by RAII.
// Using std::string as return and parameter type:
std::string AcceptsAndReturnsSTLString(std::string name) {
std::cout<<"The passed name: "<<name<<std::endl;
// Create and return an STL-string from c-string literal:
return "Pamela";
}
// Create and accept STL-string from a c-string literal:
std::string result = AcceptsAndReturnsSTLString("Sandra");
// > The passed name: Sandra
// result = "Pamela"
5
Avoiding Object Copies – Example: std::string
● Means to avoid multiple copying of std::strings:
– Pass pointers to std::strings to functions (i.e. back to the idea "pass by reference").
– Return pointers to std::strings created in the heap or freestore.
– … let's rewrite AcceptsAndReturnsSTLString() accordingly:
• The means work: neither sandra nor "Pamela" is copied, but created only once.
• But dealing with freestore and pointers to avoid copies is cumbersome.
– Therefor C++ introduced another means to avoid copies: references.
// Using std::string* as return and parameter type:
std::string* AcceptsAndReturnsSTLString(std::string* name) {
std::cout<<"The passed name: "<<*name<<std::endl;
// Create std::string on freestore and return it.
return new std::string("Pamela");
}
// Create std::string on the stack and pass a pointer to that
// string to the function:
std::string sandra = "Sandra";
std::string* result = AcceptsAndReturnsSTLString(&sandra);
// > The passed name: Sandra
// result = pointer to "Pamela"
delete result;
6
C++ References
● We can, e.g., use std::string-references as parameter types.
– (For the time being, we'll only discuss parameters of reference type.)
● Syntactic peculiarities of C++ references:
– A C++ reference has a syntax decoration of the referenced type with the &-symbol.
– (+) When an argument is passed to a reference parameter, no extra syntax is involved.
● Using reference parameters leads to more unobtrusive code than with pointer parameters.
– (+) References can also be used as local variables and fields, but it leads to questionable code.
– (-) References need to be initialized in opposite to pointers!
– (-) References do have no notion of "nullity" like pointers (pointers can be 0).
– (-) Functions differing only in the "reference-ness" of its parameters do not overload.
// Create std::string on stack and pass it to the function:
std::string pamela = "Pamela";
AcceptsSTLString(pamela); // Here: No extra syntax!
// Questionable! Field as C++ reference.
class Foo {
int& refToInt;
public:
// The field refToInt needs to be initialized:
Foo(int i) : refToInt(i){} // Initializer list needed!
};
// Questionable! Local variable as C++ reference.
int i = 23;
// The reference refToInt needs to be initialized:
int& refToInt = i;
// Using an std::string-reference as parameter type:
void AcceptsSTLString(std::string& name) {
std::cout<<"The passed name: "<<name<<std::endl;
}
7
Tracing Object Lifetime
● Let's reuse the type PersonLitmus with tracing messages.
– Calling the function accepting PersonLitmus leads to anonymous copies:
– Calling the function accepting PersonLimus& avoids anonymous copies:
class PersonLitmus { // Shows, when an instance is
public: // created and destroyed.
PersonLitmus() {
std::cout<<"Person created"<<std::endl;
}
~PersonLitmus() {
std::cout<<"Person destroyed"<<std::endl;
}
};
void AcceptsPerson(PersonLitmus person) {
/* pass */
}
void AcceptsPersonByRef(PersonLitmus& person) {
/* pass */
}
PersonLitmus person;
// >Person created
AcceptsPerson(person);
// >Person destroyed (destroys anonymous copy)
// >Person destroyed (destroys person)
PersonLitmus person;
// >Person created
AcceptsPersonByRef(person);
// >Person destroyed (destroys person)
8
Anonymous Object Copies
● Let's review the example without reference parameters:
● This example shows that more objects seem to be destroyed than created!
– What the heck is going on here? The ctor was only called once, but the dtor twice!
● By default, C++ passes/returns objects to/from functions by value, creating copies.
● The answer for these unbalanced dtors: temporary copies of those objects are created.
● It's time to clarify the source of the anonymous copies: copy constructors (cctors).
– The cctor is called on copying objects!
void AcceptsPerson(PersonLitmus person) {
/* pass */
}
PersonLitmus person;
// >Person created
AcceptsPerson(person);
// >Person destroyed (destroys anonymous copy)
// >Person destroyed (destroys person)
9
Tracing Object Copies
● Implementing the copy constructor w/ tracing makes the creation of copies visible.
– If not explicitly programmed, the cctor will be generated automatically (like dctors/dtors are).
● Syntactic peculiarities of cctors:
– It has exactly one (non-defaulted) parameter: a reference of the surrounding type.
– The cctor obeys to the same syntactic rules like other ctors do.
– A type's cctor will be automatically called, when the type is passed/returned by value.
class PersonLitmus { // Shows when an instance is
public: // created, copied and destroyed.
PersonLitmus() {
std::cout<<"Person created"<<std::endl;
}
PersonLitmus(PersonLitmus& original) {
std::cout<<"Person copied"<<std::endl;
}
~PersonLitmus() {
std::cout<<"Person destroyed"<<std::endl;
}
};
void AcceptsPerson(PersonLitmus person) {
/* pass */
}
PersonLitmus person;
// >Person created
AcceptsPerson(person);
// >Person copied (anon. copy created)
// >Person destroyed (destroys anon. copy)
// >Person destroyed (destroys person)
● Why needs a cctor to accept a reference of the
surrounding type?
● If the cctor accepted a non-reference parameter
of the surrounding type, the cctor would call
itself recursively up to infinity!
● Cctors' parameters are allowed to be annotated
with all kinds of cv-qualified references, they also
overload (That should not be done on purpose!). -
The rules for matching overloads are complex
and will not be discussed here.
● Cctors can have more than the obligatory
parameter, but the remaining parameters need to
be notated with default arguments.
10
The Problem with shared Data – Copying
● Let's revisit the type Person that handles dynamic data.
– Passing an object of type Person by value leads to undefined behavior in the dtor!
● The automatically created cctor just copies all fields, not the referenced memory.
– It results in Person-copies having copied pointers to the same location in memory (name).
– Every Person-copy will try to delete (dtor) the same location in memory via its pointer-copy.
class Person { // (members hidden)
char* name;
public:
Person(const char* name) {
if (name) {
this->name = new char[std::strlen(name) + 1];
std::strcpy(this->name, name);
}
}
~Person() {
delete[] this->name;
}
};
Person nico("nico");
AcceotsPerson(nico);
// Undefined behavior: crash!
// Virtually something like this is executed:
Person nico("nico");
Person tmp;
tmp.name(nico.name); // Copies the pointer.
AcceptsPerson(tmp);
void AcceptsPerson(PersonLitmus person) {
/* pass */
}
● The syntax tmp.name(nico.name) is not legal, a
cctor can't be called like so. - But this is what's
happing underneath basically.
11
The automatically created Copy Constructor
● When nico is passed to AcceptsPerson() a copy of nico is created.
– The automatically generated cctor does only copy nico's fields (i.e. name).
– The cctor doesn't copy the occupied memory in depth, we call this a shallow copy.
– The automatically generated cctor is public also for classes!
● We've two Persons' name-fields both pointing to the same location in the freestore.
– This leads to dtors of two Persons feeling responsible for name's memory.
– => In effect the same memory will be freed twice!
– We hurt a fundamental rule when dealing w/ dynamic memory: We should not free dynamically created content more than once!
{
Person nico("nico");
nico
nico.name0x00076f2c
0'c' 'o''i''n'
AcceptsPerson(nico);
(temporary Person)
(tmp).name0x00076f2c
} // Undefined behavior when nico's scope ends!
0'c' 'o''i''n'
nico's dtor
the copy's dtor
:-(
class Person { // (members hidden)
char* name;
};
12
The Copy Constructor
● The solution: we've to implement the cctor explicitly!
– We have to implement the cctor to make a deep copy of the original.
● The cctor just accepts the original object and makes a deep copy.
– std::string provides a cctor.
class Person { // (members hidden)
char* name;
public:
Person(const char* name) {
if (name) {
this->name = new char[std::strlen(name) + 1];
std::strcpy(this->name, name);
}
}
Person(Person& original) { // The cctor.
name = new char[std::strlen(original.name) + 1];
std::strcpy(name, original.name);
}
~Person() {
delete[] this->name;
}
};
{
Person nico("nico");
AcceptsPerson(nico);
} // Fine!
nico
nico.name0x00076f2c
0'c' 'o''i''n'
(temporary Person)
(tmp).name0x0007ff45
nico's dtor
the copy's dtor
0'c' 'o''i''n'
void AcceptsPerson(Person person) {
/* pass */
}
13
Implicit and Explicit Conversion Constructors
● In fact we have already overloaded an operator in the UDT Person!
● Every single-parameter ctor defines an implicit conversion ctor.
●
E.g. a const char* passed to AcceptsPerson() will be implicitly converted to a Person.
●
Also std::string has such an implicit conversion ctor: string::string(const char*).
● Sometimes implicit conversion is not desired for single-parameter ctors.
● (E.g. to avoid "surprises" with overloaded functions.)
● Therefor C++ allows conversion ctors to be marked as explicit conversion ctors.
class Person { // (members hidden)
public:
Person(const char* name) {
/* pass */
}
};
void AcceptsPerson(Person person) {
/* pass */
}
void AcceptsPerson(Person person) {
/* pass */
}
class Person { // (members hidden)
public:
explicit Person(const char* name) {
/* pass */
}
};
AcceptsPerson("nico"); // Ok!
AcceptsPerson("nico"); // Invalid! No implicit conversion!
AcceptsPerson(Person("nico")); // Ok! Explicit conversion.
● HandlePerson(Person) and HandlePerson(const
Person&) would not be called, if
HandlePerson(const char*) existed and
HandlePerson("nico") be called. The best match
is taken, implicit conversion and temporary copies
are avoided at overload resolution.
14
Problems with Reference Parameters
● After the discussion concerning costly copying, let's use references for all UDTsto avoid (deep) copying in future! - But
there are problems:
– 1. With functions accepting references we could modify the original argument!
●
Very often this happens accidentally, here it is shown in a more radical example:
– 2. Functions accepting references can't cope w/ objects created by implicit conversions.
● E.g. a const char* can't be implicitly converted into an std::string and passed to an std::string&:
● This yields a compiler message like "Non l-value can't be bound to non-const reference."
void PrintToConsole(std::string& text) {
std::cout<<text<<std::endl;
// Oups! Modified the parameter and the argument!
text = "Angela";
}
void PrintToConsole(std::string& text) {
std::cout<<text<<std::endl;
}
std::string pamela = "Pamela";
PrintToConsole(pamela);
// >Pamela
std::cout<<pamela<<std::endl;
// >Angela (Oups! The content of pamela has been modified!)
// Invalid! Literal const char* can't be passed!
PrintToConsole("Pamela");
● An object created by implicit conversion is a
temporary object, and as such it can't be an
lvalue, therefor this message happens to appear.
15
Const References
● The discussed problems can be solved with const references (const&).
● const& parameters can not be modified (accidentally), e.g. assigned to.
– const std::string& are esp. important as std::string is a mutable string type.
– The same is valid for const pointers (e.g. also as parameters) as well.
● const& parameters can accept temporary anonymous conversion copies.
– A const char* can be implicitly converted into an std::string and passed to a const std::string&:
void PrintToConsole(const std::string& text) {
std::cout<<text<<std::endl;
// Invalid! Const parameter.
text = "Angela";
}
void PrintToConsole(const std::string& text) {
std::cout<<text<<std::endl;
}
std::string pamela = "Pamela";
PrintToConsole(pamela);
// >Pamela
// Fine! Literal const char* can be passed now!
PrintToConsole("Pamela");
● This is a very important fact: const char* have
been non-modifiable, but the STL type std::string
is mutable! With const std::strings, (and const&
thereof) we can get const char*'s safety aspect
back.
● Strings in Java and .Net are not mutable. On that
platforms string operations create new strings
instead of modifying the string on which they
have been called.
16
The need for const Member Functions
● Ok! Then let's use const& for all UDTs! - But there are still problems:
– We can't call all the member functions via a const&.
● C++ assumes that all member functions potentially modify the target object.
– Calling member functions on const& and const pointers is generally not allowed.
– Compilers can't predict, whether called member functions modify the object.
● To solve this problem C++ introduces so called const member functions.
– Only const member functions can be called on const objects.
class Date { // (members hidden)
int month;
public:
int GetMonth() {
return month;
}
};
void PrintMonth(const Date& date) {
// Invalid! Can't call non-const member function on const&.
std::cout<<date.GetMonth()<<std::endl;
}
void PrintMonth(const Date* date) {
// Invalid! Can't call non-const member function on const pointer.
std::cout<<date->GetMonth()<<std::endl;
}
17
Implementing const Member Functions
● To make a member function const: just add the const suffix to declaration and definition.
● In the implementation of a const member function
– fields can only be read,
– only free functions, static member functions and other const member functions can be called.
– The const-ness of const member functions is kind of "closed".
– std::string provides a set of const member functions.
● Member functions and const/volatile qualifiers (cv-qualifiers):
– We can have a const and a non-const overload of a member function in C++.
– C++ also allows the definition of volatile and const volatile member functions.
● Non-const, const, volatile and const volatile do overload!
class Date { // (members hidden)
int month;
public:
int GetMonth() const {
return month;
}
};
void PrintMonth(const Date& date) {
// Fine! Date::GetMonth() is a const member function.
std::cout<<date.GetMonth()<<std::endl;
}
void PrintMonth(const Date* date) {
// Fine! Date::GetMonth() is a const member function.
std::cout<<date->GetMonth()<<std::endl;
}
● What is "volatile"?
● If an object is declared volatile, the C/C++
compiler assumes that its value could change
anytime by any thread of execution. - Accessing
a volatile variable is interpreted as direct
memory read/write w/o caching.
● The cv-qualification needs to be repeated on a
non-inline definition, because cv-qualifiers
overload.
● There can be no const static member functions.
18
C++ References summarized: Our Rules for References
● C++ references have been introduced to overload operators, because:
– they provide an unobtrusive syntax to make using operators intuitively,
– they prevent call by value and
– const& allow passing temporary objects, so its also good for non-operator functions.
● Important features of C++ references:
– They're similar to pointers as call by reference, aliasing and data sharing is concerned.
– References can't be uninitialized and they have no notion of "nullity".
● Some widely used industry standards that we're going to adopt as rules:
– (+) Primary use const& for UDT parameters, and avoid passing UDTs by value!
– (+) Pass fundamental types only by value or pointer, the compiler cares for optimization.
– (+) If we need to modify passed objects we should use non-const pointers.
– (-) Don't use references to replace pointers only for syntax purposes in order to modify the passed objects!
● If we see the discussed rules hurt, then this is
what we call a "code smell". If the code is under
our control, we should refactor it to obey these
rules and prove the functionality with unit tests.
● UDTs should be passed by const&, if they are not
already being passed as pointer.
19
Circumventing const: mutable Fields
● We can't modify the target object (i.e. this) in const member functions.
– We can not write a const Date::SetMonth() member function like so:
● Often real life objects need to differentiate logical from physical const-ness.
– I.e. an object presents const member functions that need to write some fields.
– C++ provides a backdoor: mutable fields can be written in const member functions.
class Date { // (members hidden)
public:
void SetMonth(int month) const {
this->month = month; // Invalid! this->month is readonly
} // in a const member function.
};
class Date { // (members hidden)
mutable int monthAccessed;
public:
int GetMonth() const {
++monthAccessed; // Fine! Mutable fields can be written
return month; // in const member functions.
}
};
20
Cheating const: Casting const-ness away
● After discussing how to avoid copies, implicit conversion andstd::string, we'd better use const std::string& as function
parameter type always.
– But this also means that passed std::strings can't be modified!
● There is a way to call non-const member functions on const objects!
– const-ness can be casted away in C++ with the const_cast operator:
● Casting const-ness away is dangerous! - It's undefined with temporary objects.
– Let's never use const_cast, unless we've a very good reason to use it!
void Clear(const std::string& name) {
name.erase(); // Invalid! Can't call non-const member function on name.
} // That makes sense! std::string::erase() can't be a const member function!
void ClearConst(const std::string& name) {
std::string& nonConstName = const_cast<std::string&>(name);
nonConstName.erase(); // Ok! nonConstName is not const!
}
std::string nico("nico")
ClearConst(nico); // Ok!
std::cout<<nico<<std::endl;
// > // (empty)
ClearConst("nico"); // Undefined behaviour! The literal "nico"
// is really const and can't be erased!
std::cout<<nico<<std::endl;
// > // (empty)
21
"Const-incorrectness"
● All fields of a const object are also const, we can only call const member functions on it.
● Assume the UDT Person and the const member function GetName() in (1).
● When we define a const instance of Person, the UDT virtually changes to (2).
● Was all our work for const-ness for good? - Well, our UDT isn't yet const-correct!
class Person { // (1) (members hidden)
public:
char* name; // Only for demo!
char* GetName() const {
return this->name;
}
};
const Person nico("nico"); // But here the surprises:
// These operations are allowed(!):
std::strcpy(nico.name, "joe");
// The memory to which nico.name points to is not const!
std::strcpy(nico.GetName(), "jim");
// The memory to which nico.name points to is not const!
// - GetName() just returns a pointer.
class Person { // (2) (members hidden)
public:
char* const name;
char* GetName() const {
return this->name;
}
};
// We already know this fact:
const Person nico("nico");
// This is not allowed:
nico.name = 0; // Invalid!
// The field nico.name is a const pointer!
● Another way to understand const correctness:
const member functions need to be balanced to
other const member functions and their return
types. Finally, const correct types allow the
creation of immutable types in C++. (The support
for immutable types is not so good in C#.)
22
Const-correctness
● The just encountered problem is that const-ness is not deep enough!
– The const-ness of an object only affects the fields, not the memory the fields refer to.
●
This problem is relevant for pointers as well as for references.
– const members functions don't shield us from modifiable referred memory!
● To make Person/GetName() const-correct, we'll make the field name private and fix GetName() to return a const char*
instead of a char*.
– 1. The field name can't be accessed from "outside".
– 2. GetName() returns a const char*, it doesn't allow writing memory referenced byname.
● const correct: Generally return const pointers/references from const member function.
class Person { // (members hidden)
char* name;
public:
const char* GetName() const {
return this->name;
}
};
const Person nico("nico"); // Now Person is const correct:
std::strcpy(nico.name, "joe"); // Invalid! name is private!
std::strcpy(nico.GetName(), "jim"); // Invalid! GetName()
// returns a const char* that doesn't allow to write the
// referred memory.
23
Thank you!

More Related Content

What's hot

Core csharp and net quick reference
Core csharp and net quick referenceCore csharp and net quick reference
Core csharp and net quick referenceilesh raval
 
Regular types in C++
Regular types in C++Regular types in C++
Regular types in C++Ilio Catallo
 
C interview-questions-techpreparation
C interview-questions-techpreparationC interview-questions-techpreparation
C interview-questions-techpreparationKushaal Singla
 
Tokens expressionsin C++
Tokens expressionsin C++Tokens expressionsin C++
Tokens expressionsin C++HalaiHansaika
 
C# Cheat Sheet
C# Cheat SheetC# Cheat Sheet
C# Cheat SheetGlowTouch
 
Exercises on Advances in Verification Methodologies
Exercises on Advances in Verification Methodologies Exercises on Advances in Verification Methodologies
Exercises on Advances in Verification Methodologies Ramdas Mozhikunnath
 
Project Lambda - Closures after all?
Project Lambda - Closures after all?Project Lambda - Closures after all?
Project Lambda - Closures after all?Andreas Enbohm
 
Java string handling
Java string handlingJava string handling
Java string handlingSalman Khan
 
C cheat sheet for varsity (extreme edition)
C cheat sheet for varsity (extreme edition)C cheat sheet for varsity (extreme edition)
C cheat sheet for varsity (extreme edition)Saifur Rahman
 
String java
String javaString java
String java774474
 
C++ Advanced
C++ AdvancedC++ Advanced
C++ AdvancedVivek Das
 
Real World Haskell: Lecture 6
Real World Haskell: Lecture 6Real World Haskell: Lecture 6
Real World Haskell: Lecture 6Bryan O'Sullivan
 
Strings In OOP(Object oriented programming)
Strings In OOP(Object oriented programming)Strings In OOP(Object oriented programming)
Strings In OOP(Object oriented programming)Danial Virk
 
Demystifying Shapeless
Demystifying Shapeless Demystifying Shapeless
Demystifying Shapeless Jared Roesch
 

What's hot (18)

Linked list
Linked listLinked list
Linked list
 
Core csharp and net quick reference
Core csharp and net quick referenceCore csharp and net quick reference
Core csharp and net quick reference
 
R programming Language
R programming LanguageR programming Language
R programming Language
 
Regular types in C++
Regular types in C++Regular types in C++
Regular types in C++
 
C interview-questions-techpreparation
C interview-questions-techpreparationC interview-questions-techpreparation
C interview-questions-techpreparation
 
Tokens expressionsin C++
Tokens expressionsin C++Tokens expressionsin C++
Tokens expressionsin C++
 
C# Cheat Sheet
C# Cheat SheetC# Cheat Sheet
C# Cheat Sheet
 
Exercises on Advances in Verification Methodologies
Exercises on Advances in Verification Methodologies Exercises on Advances in Verification Methodologies
Exercises on Advances in Verification Methodologies
 
Project Lambda - Closures after all?
Project Lambda - Closures after all?Project Lambda - Closures after all?
Project Lambda - Closures after all?
 
Java string handling
Java string handlingJava string handling
Java string handling
 
C cheat sheet for varsity (extreme edition)
C cheat sheet for varsity (extreme edition)C cheat sheet for varsity (extreme edition)
C cheat sheet for varsity (extreme edition)
 
String java
String javaString java
String java
 
C++ Advanced
C++ AdvancedC++ Advanced
C++ Advanced
 
Ruby Programming Assignment Help
Ruby Programming Assignment HelpRuby Programming Assignment Help
Ruby Programming Assignment Help
 
Chapter 2
Chapter 2Chapter 2
Chapter 2
 
Real World Haskell: Lecture 6
Real World Haskell: Lecture 6Real World Haskell: Lecture 6
Real World Haskell: Lecture 6
 
Strings In OOP(Object oriented programming)
Strings In OOP(Object oriented programming)Strings In OOP(Object oriented programming)
Strings In OOP(Object oriented programming)
 
Demystifying Shapeless
Demystifying Shapeless Demystifying Shapeless
Demystifying Shapeless
 

Similar to (4) cpp abstractions references_copies_and_const-ness

Similar to (4) cpp abstractions references_copies_and_const-ness (20)

c++ UNIT II.pptx
c++ UNIT II.pptxc++ UNIT II.pptx
c++ UNIT II.pptx
 
Introduction to C#
Introduction to C#Introduction to C#
Introduction to C#
 
L6
L6L6
L6
 
Learn c++ Programming Language
Learn c++ Programming LanguageLearn c++ Programming Language
Learn c++ Programming Language
 
(4) cpp automatic arrays_pointers_c-strings
(4) cpp automatic arrays_pointers_c-strings(4) cpp automatic arrays_pointers_c-strings
(4) cpp automatic arrays_pointers_c-strings
 
Smart Pointers in C++
Smart Pointers in C++Smart Pointers in C++
Smart Pointers in C++
 
Introduction to c_plus_plus (6)
Introduction to c_plus_plus (6)Introduction to c_plus_plus (6)
Introduction to c_plus_plus (6)
 
Introduction to c_plus_plus
Introduction to c_plus_plusIntroduction to c_plus_plus
Introduction to c_plus_plus
 
C Programming - Refresher - Part IV
C Programming - Refresher - Part IVC Programming - Refresher - Part IV
C Programming - Refresher - Part IV
 
CS225_Prelecture_Notes 2nd
CS225_Prelecture_Notes 2ndCS225_Prelecture_Notes 2nd
CS225_Prelecture_Notes 2nd
 
(2) cpp imperative programming
(2) cpp imperative programming(2) cpp imperative programming
(2) cpp imperative programming
 
Learning C++ - Introduction to c++ programming 1
Learning C++ - Introduction to c++ programming 1Learning C++ - Introduction to c++ programming 1
Learning C++ - Introduction to c++ programming 1
 
Modern C++
Modern C++Modern C++
Modern C++
 
Return of c++
Return of c++Return of c++
Return of c++
 
Cpp17 and Beyond
Cpp17 and BeyondCpp17 and Beyond
Cpp17 and Beyond
 
smart pointers are unique concept to avoid memory leakage
smart pointers are unique concept to avoid memory leakagesmart pointers are unique concept to avoid memory leakage
smart pointers are unique concept to avoid memory leakage
 
Presentation
PresentationPresentation
Presentation
 
Csharp_mahesh
Csharp_maheshCsharp_mahesh
Csharp_mahesh
 
Lecture5
Lecture5Lecture5
Lecture5
 
Basics of C
Basics of CBasics of C
Basics of C
 

More from Nico Ludwig

Grundkurs fuer excel_part_v
Grundkurs fuer excel_part_vGrundkurs fuer excel_part_v
Grundkurs fuer excel_part_vNico Ludwig
 
Grundkurs fuer excel_part_iv
Grundkurs fuer excel_part_ivGrundkurs fuer excel_part_iv
Grundkurs fuer excel_part_ivNico Ludwig
 
Grundkurs fuer excel_part_iii
Grundkurs fuer excel_part_iiiGrundkurs fuer excel_part_iii
Grundkurs fuer excel_part_iiiNico Ludwig
 
Grundkurs fuer excel_part_ii
Grundkurs fuer excel_part_iiGrundkurs fuer excel_part_ii
Grundkurs fuer excel_part_iiNico Ludwig
 
Grundkurs fuer excel_part_i
Grundkurs fuer excel_part_iGrundkurs fuer excel_part_i
Grundkurs fuer excel_part_iNico Ludwig
 
(1) gui history_of_interactivity
(1) gui history_of_interactivity(1) gui history_of_interactivity
(1) gui history_of_interactivityNico Ludwig
 
(1) gui history_of_interactivity
(1) gui history_of_interactivity(1) gui history_of_interactivity
(1) gui history_of_interactivityNico Ludwig
 
New c sharp4_features_part_vi
New c sharp4_features_part_viNew c sharp4_features_part_vi
New c sharp4_features_part_viNico Ludwig
 
New c sharp4_features_part_v
New c sharp4_features_part_vNew c sharp4_features_part_v
New c sharp4_features_part_vNico Ludwig
 
New c sharp4_features_part_iv
New c sharp4_features_part_ivNew c sharp4_features_part_iv
New c sharp4_features_part_ivNico Ludwig
 
New c sharp4_features_part_iii
New c sharp4_features_part_iiiNew c sharp4_features_part_iii
New c sharp4_features_part_iiiNico Ludwig
 
New c sharp4_features_part_ii
New c sharp4_features_part_iiNew c sharp4_features_part_ii
New c sharp4_features_part_iiNico Ludwig
 
New c sharp4_features_part_i
New c sharp4_features_part_iNew c sharp4_features_part_i
New c sharp4_features_part_iNico Ludwig
 
New c sharp3_features_(linq)_part_v
New c sharp3_features_(linq)_part_vNew c sharp3_features_(linq)_part_v
New c sharp3_features_(linq)_part_vNico Ludwig
 
New c sharp3_features_(linq)_part_iv
New c sharp3_features_(linq)_part_ivNew c sharp3_features_(linq)_part_iv
New c sharp3_features_(linq)_part_ivNico Ludwig
 
New c sharp3_features_(linq)_part_iv
New c sharp3_features_(linq)_part_ivNew c sharp3_features_(linq)_part_iv
New c sharp3_features_(linq)_part_ivNico Ludwig
 
New c sharp3_features_(linq)_part_iii
New c sharp3_features_(linq)_part_iiiNew c sharp3_features_(linq)_part_iii
New c sharp3_features_(linq)_part_iiiNico Ludwig
 
New c sharp3_features_(linq)_part_ii
New c sharp3_features_(linq)_part_iiNew c sharp3_features_(linq)_part_ii
New c sharp3_features_(linq)_part_iiNico Ludwig
 

More from Nico Ludwig (20)

Grundkurs fuer excel_part_v
Grundkurs fuer excel_part_vGrundkurs fuer excel_part_v
Grundkurs fuer excel_part_v
 
Grundkurs fuer excel_part_iv
Grundkurs fuer excel_part_ivGrundkurs fuer excel_part_iv
Grundkurs fuer excel_part_iv
 
Grundkurs fuer excel_part_iii
Grundkurs fuer excel_part_iiiGrundkurs fuer excel_part_iii
Grundkurs fuer excel_part_iii
 
Grundkurs fuer excel_part_ii
Grundkurs fuer excel_part_iiGrundkurs fuer excel_part_ii
Grundkurs fuer excel_part_ii
 
Grundkurs fuer excel_part_i
Grundkurs fuer excel_part_iGrundkurs fuer excel_part_i
Grundkurs fuer excel_part_i
 
(2) gui drawing
(2) gui drawing(2) gui drawing
(2) gui drawing
 
(2) gui drawing
(2) gui drawing(2) gui drawing
(2) gui drawing
 
(1) gui history_of_interactivity
(1) gui history_of_interactivity(1) gui history_of_interactivity
(1) gui history_of_interactivity
 
(1) gui history_of_interactivity
(1) gui history_of_interactivity(1) gui history_of_interactivity
(1) gui history_of_interactivity
 
New c sharp4_features_part_vi
New c sharp4_features_part_viNew c sharp4_features_part_vi
New c sharp4_features_part_vi
 
New c sharp4_features_part_v
New c sharp4_features_part_vNew c sharp4_features_part_v
New c sharp4_features_part_v
 
New c sharp4_features_part_iv
New c sharp4_features_part_ivNew c sharp4_features_part_iv
New c sharp4_features_part_iv
 
New c sharp4_features_part_iii
New c sharp4_features_part_iiiNew c sharp4_features_part_iii
New c sharp4_features_part_iii
 
New c sharp4_features_part_ii
New c sharp4_features_part_iiNew c sharp4_features_part_ii
New c sharp4_features_part_ii
 
New c sharp4_features_part_i
New c sharp4_features_part_iNew c sharp4_features_part_i
New c sharp4_features_part_i
 
New c sharp3_features_(linq)_part_v
New c sharp3_features_(linq)_part_vNew c sharp3_features_(linq)_part_v
New c sharp3_features_(linq)_part_v
 
New c sharp3_features_(linq)_part_iv
New c sharp3_features_(linq)_part_ivNew c sharp3_features_(linq)_part_iv
New c sharp3_features_(linq)_part_iv
 
New c sharp3_features_(linq)_part_iv
New c sharp3_features_(linq)_part_ivNew c sharp3_features_(linq)_part_iv
New c sharp3_features_(linq)_part_iv
 
New c sharp3_features_(linq)_part_iii
New c sharp3_features_(linq)_part_iiiNew c sharp3_features_(linq)_part_iii
New c sharp3_features_(linq)_part_iii
 
New c sharp3_features_(linq)_part_ii
New c sharp3_features_(linq)_part_iiNew c sharp3_features_(linq)_part_ii
New c sharp3_features_(linq)_part_ii
 

Recently uploaded

ChatGPT and Beyond - Elevating DevOps Productivity
ChatGPT and Beyond - Elevating DevOps ProductivityChatGPT and Beyond - Elevating DevOps Productivity
ChatGPT and Beyond - Elevating DevOps ProductivityVictorSzoltysek
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdfSandro Moreira
 
Introduction to use of FHIR Documents in ABDM
Introduction to use of FHIR Documents in ABDMIntroduction to use of FHIR Documents in ABDM
Introduction to use of FHIR Documents in ABDMKumar Satyam
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Victor Rentea
 
Stronger Together: Developing an Organizational Strategy for Accessible Desig...
Stronger Together: Developing an Organizational Strategy for Accessible Desig...Stronger Together: Developing an Organizational Strategy for Accessible Desig...
Stronger Together: Developing an Organizational Strategy for Accessible Desig...caitlingebhard1
 
Choreo: Empowering the Future of Enterprise Software Engineering
Choreo: Empowering the Future of Enterprise Software EngineeringChoreo: Empowering the Future of Enterprise Software Engineering
Choreo: Empowering the Future of Enterprise Software EngineeringWSO2
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamUiPathCommunity
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAndrey Devyatkin
 
AI in Action: Real World Use Cases by Anitaraj
AI in Action: Real World Use Cases by AnitarajAI in Action: Real World Use Cases by Anitaraj
AI in Action: Real World Use Cases by AnitarajAnitaRaj43
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingEdi Saputra
 
WSO2 Micro Integrator for Enterprise Integration in a Decentralized, Microser...
WSO2 Micro Integrator for Enterprise Integration in a Decentralized, Microser...WSO2 Micro Integrator for Enterprise Integration in a Decentralized, Microser...
WSO2 Micro Integrator for Enterprise Integration in a Decentralized, Microser...WSO2
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native ApplicationsWSO2
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfOrbitshub
 
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Bhuvaneswari Subramani
 
WSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businesspanagenda
 
Platformless Horizons for Digital Adaptability
Platformless Horizons for Digital AdaptabilityPlatformless Horizons for Digital Adaptability
Platformless Horizons for Digital AdaptabilityWSO2
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FMESafe Software
 
JohnPollard-hybrid-app-RailsConf2024.pptx
JohnPollard-hybrid-app-RailsConf2024.pptxJohnPollard-hybrid-app-RailsConf2024.pptx
JohnPollard-hybrid-app-RailsConf2024.pptxJohnPollard37
 
Modernizing Legacy Systems Using Ballerina
Modernizing Legacy Systems Using BallerinaModernizing Legacy Systems Using Ballerina
Modernizing Legacy Systems Using BallerinaWSO2
 

Recently uploaded (20)

ChatGPT and Beyond - Elevating DevOps Productivity
ChatGPT and Beyond - Elevating DevOps ProductivityChatGPT and Beyond - Elevating DevOps Productivity
ChatGPT and Beyond - Elevating DevOps Productivity
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf
 
Introduction to use of FHIR Documents in ABDM
Introduction to use of FHIR Documents in ABDMIntroduction to use of FHIR Documents in ABDM
Introduction to use of FHIR Documents in ABDM
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
Stronger Together: Developing an Organizational Strategy for Accessible Desig...
Stronger Together: Developing an Organizational Strategy for Accessible Desig...Stronger Together: Developing an Organizational Strategy for Accessible Desig...
Stronger Together: Developing an Organizational Strategy for Accessible Desig...
 
Choreo: Empowering the Future of Enterprise Software Engineering
Choreo: Empowering the Future of Enterprise Software EngineeringChoreo: Empowering the Future of Enterprise Software Engineering
Choreo: Empowering the Future of Enterprise Software Engineering
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
AI in Action: Real World Use Cases by Anitaraj
AI in Action: Real World Use Cases by AnitarajAI in Action: Real World Use Cases by Anitaraj
AI in Action: Real World Use Cases by Anitaraj
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
WSO2 Micro Integrator for Enterprise Integration in a Decentralized, Microser...
WSO2 Micro Integrator for Enterprise Integration in a Decentralized, Microser...WSO2 Micro Integrator for Enterprise Integration in a Decentralized, Microser...
WSO2 Micro Integrator for Enterprise Integration in a Decentralized, Microser...
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
 
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
 
WSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering Developers
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
Platformless Horizons for Digital Adaptability
Platformless Horizons for Digital AdaptabilityPlatformless Horizons for Digital Adaptability
Platformless Horizons for Digital Adaptability
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
JohnPollard-hybrid-app-RailsConf2024.pptx
JohnPollard-hybrid-app-RailsConf2024.pptxJohnPollard-hybrid-app-RailsConf2024.pptx
JohnPollard-hybrid-app-RailsConf2024.pptx
 
Modernizing Legacy Systems Using Ballerina
Modernizing Legacy Systems Using BallerinaModernizing Legacy Systems Using Ballerina
Modernizing Legacy Systems Using Ballerina
 

(4) cpp abstractions references_copies_and_const-ness

  • 2. 2 TOC ● (4) C++ Abstractions – The STL Type std::string – C++ References and Const References – More on RAII: ● Copy Constructors ● Temporary and Anonymous Objects ● Type Conversion – Const-ness in C++ ● Const Member Functions ● Const Correctness ● Mutable Fields ● Sources: – Bjarne Stroustrup, The C++ Programming Language – John Lakos, Large-Scale C++ Software Design
  • 3. 3 C-Strings revisited ● In the last lectures we talked about the encapsulation of concepts and RAII. – Now it's time to make use of RAII to make our programming tasks easier. ● E.g. we should apply RAII to encapsulate c-strings, thus enhancing: – creation, – assignment, – copying and – operations on c-strings – by encapsulating the tedious memory management around c-strings. ● The good news: we don't have to create a new UDT, we can use STL-strings! – STL-strings are represented by the C++ standard type std::string. – The type std::string is defined in <string>. – std::string provides important RAII features that make using std::string intuitive. ● Also the ugly 0-termination is to be encapsulated. ● The type std::string is a very good example of encapsulation. The design of std::string makes working with strings very comfortable, safe and productive, esp. because RAII has been implemented in std::string. ● Many different libraries implemented "their" string types different from std::string (mutable string types, immutable string types, reference counted string types etc.), but we'll only use const char* or std::string in this course.
  • 4. 4 The UDT std::string ● To use STL-strings we have to include <string> and keep on going with std::string: ● The type std::string can be used like a fundamental type, e.g. as return/parameter type: ● Hooray! - A simple-to-use string type in C++! But there is a performance problem: – Due to RAII, std::strings are copied when passed to and returned from functions. – It means that the encapsulated c-strings (char arrays) are allocated and freed multiply. ● This is, e.g., done by ctors and dtors which manage RAII. – Can we improve this situation? std::string name = "Lola"; // Creation std::string otherName = name; // Assignment/Copying std::string subString = name.substr(2, 2); // Substring: a member function of std::string (result: "la") // The memory of the used strings will be managed (e.g. also freed) by RAII. // Using std::string as return and parameter type: std::string AcceptsAndReturnsSTLString(std::string name) { std::cout<<"The passed name: "<<name<<std::endl; // Create and return an STL-string from c-string literal: return "Pamela"; } // Create and accept STL-string from a c-string literal: std::string result = AcceptsAndReturnsSTLString("Sandra"); // > The passed name: Sandra // result = "Pamela"
  • 5. 5 Avoiding Object Copies – Example: std::string ● Means to avoid multiple copying of std::strings: – Pass pointers to std::strings to functions (i.e. back to the idea "pass by reference"). – Return pointers to std::strings created in the heap or freestore. – … let's rewrite AcceptsAndReturnsSTLString() accordingly: • The means work: neither sandra nor "Pamela" is copied, but created only once. • But dealing with freestore and pointers to avoid copies is cumbersome. – Therefor C++ introduced another means to avoid copies: references. // Using std::string* as return and parameter type: std::string* AcceptsAndReturnsSTLString(std::string* name) { std::cout<<"The passed name: "<<*name<<std::endl; // Create std::string on freestore and return it. return new std::string("Pamela"); } // Create std::string on the stack and pass a pointer to that // string to the function: std::string sandra = "Sandra"; std::string* result = AcceptsAndReturnsSTLString(&sandra); // > The passed name: Sandra // result = pointer to "Pamela" delete result;
  • 6. 6 C++ References ● We can, e.g., use std::string-references as parameter types. – (For the time being, we'll only discuss parameters of reference type.) ● Syntactic peculiarities of C++ references: – A C++ reference has a syntax decoration of the referenced type with the &-symbol. – (+) When an argument is passed to a reference parameter, no extra syntax is involved. ● Using reference parameters leads to more unobtrusive code than with pointer parameters. – (+) References can also be used as local variables and fields, but it leads to questionable code. – (-) References need to be initialized in opposite to pointers! – (-) References do have no notion of "nullity" like pointers (pointers can be 0). – (-) Functions differing only in the "reference-ness" of its parameters do not overload. // Create std::string on stack and pass it to the function: std::string pamela = "Pamela"; AcceptsSTLString(pamela); // Here: No extra syntax! // Questionable! Field as C++ reference. class Foo { int& refToInt; public: // The field refToInt needs to be initialized: Foo(int i) : refToInt(i){} // Initializer list needed! }; // Questionable! Local variable as C++ reference. int i = 23; // The reference refToInt needs to be initialized: int& refToInt = i; // Using an std::string-reference as parameter type: void AcceptsSTLString(std::string& name) { std::cout<<"The passed name: "<<name<<std::endl; }
  • 7. 7 Tracing Object Lifetime ● Let's reuse the type PersonLitmus with tracing messages. – Calling the function accepting PersonLitmus leads to anonymous copies: – Calling the function accepting PersonLimus& avoids anonymous copies: class PersonLitmus { // Shows, when an instance is public: // created and destroyed. PersonLitmus() { std::cout<<"Person created"<<std::endl; } ~PersonLitmus() { std::cout<<"Person destroyed"<<std::endl; } }; void AcceptsPerson(PersonLitmus person) { /* pass */ } void AcceptsPersonByRef(PersonLitmus& person) { /* pass */ } PersonLitmus person; // >Person created AcceptsPerson(person); // >Person destroyed (destroys anonymous copy) // >Person destroyed (destroys person) PersonLitmus person; // >Person created AcceptsPersonByRef(person); // >Person destroyed (destroys person)
  • 8. 8 Anonymous Object Copies ● Let's review the example without reference parameters: ● This example shows that more objects seem to be destroyed than created! – What the heck is going on here? The ctor was only called once, but the dtor twice! ● By default, C++ passes/returns objects to/from functions by value, creating copies. ● The answer for these unbalanced dtors: temporary copies of those objects are created. ● It's time to clarify the source of the anonymous copies: copy constructors (cctors). – The cctor is called on copying objects! void AcceptsPerson(PersonLitmus person) { /* pass */ } PersonLitmus person; // >Person created AcceptsPerson(person); // >Person destroyed (destroys anonymous copy) // >Person destroyed (destroys person)
  • 9. 9 Tracing Object Copies ● Implementing the copy constructor w/ tracing makes the creation of copies visible. – If not explicitly programmed, the cctor will be generated automatically (like dctors/dtors are). ● Syntactic peculiarities of cctors: – It has exactly one (non-defaulted) parameter: a reference of the surrounding type. – The cctor obeys to the same syntactic rules like other ctors do. – A type's cctor will be automatically called, when the type is passed/returned by value. class PersonLitmus { // Shows when an instance is public: // created, copied and destroyed. PersonLitmus() { std::cout<<"Person created"<<std::endl; } PersonLitmus(PersonLitmus& original) { std::cout<<"Person copied"<<std::endl; } ~PersonLitmus() { std::cout<<"Person destroyed"<<std::endl; } }; void AcceptsPerson(PersonLitmus person) { /* pass */ } PersonLitmus person; // >Person created AcceptsPerson(person); // >Person copied (anon. copy created) // >Person destroyed (destroys anon. copy) // >Person destroyed (destroys person) ● Why needs a cctor to accept a reference of the surrounding type? ● If the cctor accepted a non-reference parameter of the surrounding type, the cctor would call itself recursively up to infinity! ● Cctors' parameters are allowed to be annotated with all kinds of cv-qualified references, they also overload (That should not be done on purpose!). - The rules for matching overloads are complex and will not be discussed here. ● Cctors can have more than the obligatory parameter, but the remaining parameters need to be notated with default arguments.
  • 10. 10 The Problem with shared Data – Copying ● Let's revisit the type Person that handles dynamic data. – Passing an object of type Person by value leads to undefined behavior in the dtor! ● The automatically created cctor just copies all fields, not the referenced memory. – It results in Person-copies having copied pointers to the same location in memory (name). – Every Person-copy will try to delete (dtor) the same location in memory via its pointer-copy. class Person { // (members hidden) char* name; public: Person(const char* name) { if (name) { this->name = new char[std::strlen(name) + 1]; std::strcpy(this->name, name); } } ~Person() { delete[] this->name; } }; Person nico("nico"); AcceotsPerson(nico); // Undefined behavior: crash! // Virtually something like this is executed: Person nico("nico"); Person tmp; tmp.name(nico.name); // Copies the pointer. AcceptsPerson(tmp); void AcceptsPerson(PersonLitmus person) { /* pass */ } ● The syntax tmp.name(nico.name) is not legal, a cctor can't be called like so. - But this is what's happing underneath basically.
  • 11. 11 The automatically created Copy Constructor ● When nico is passed to AcceptsPerson() a copy of nico is created. – The automatically generated cctor does only copy nico's fields (i.e. name). – The cctor doesn't copy the occupied memory in depth, we call this a shallow copy. – The automatically generated cctor is public also for classes! ● We've two Persons' name-fields both pointing to the same location in the freestore. – This leads to dtors of two Persons feeling responsible for name's memory. – => In effect the same memory will be freed twice! – We hurt a fundamental rule when dealing w/ dynamic memory: We should not free dynamically created content more than once! { Person nico("nico"); nico nico.name0x00076f2c 0'c' 'o''i''n' AcceptsPerson(nico); (temporary Person) (tmp).name0x00076f2c } // Undefined behavior when nico's scope ends! 0'c' 'o''i''n' nico's dtor the copy's dtor :-( class Person { // (members hidden) char* name; };
  • 12. 12 The Copy Constructor ● The solution: we've to implement the cctor explicitly! – We have to implement the cctor to make a deep copy of the original. ● The cctor just accepts the original object and makes a deep copy. – std::string provides a cctor. class Person { // (members hidden) char* name; public: Person(const char* name) { if (name) { this->name = new char[std::strlen(name) + 1]; std::strcpy(this->name, name); } } Person(Person& original) { // The cctor. name = new char[std::strlen(original.name) + 1]; std::strcpy(name, original.name); } ~Person() { delete[] this->name; } }; { Person nico("nico"); AcceptsPerson(nico); } // Fine! nico nico.name0x00076f2c 0'c' 'o''i''n' (temporary Person) (tmp).name0x0007ff45 nico's dtor the copy's dtor 0'c' 'o''i''n' void AcceptsPerson(Person person) { /* pass */ }
  • 13. 13 Implicit and Explicit Conversion Constructors ● In fact we have already overloaded an operator in the UDT Person! ● Every single-parameter ctor defines an implicit conversion ctor. ● E.g. a const char* passed to AcceptsPerson() will be implicitly converted to a Person. ● Also std::string has such an implicit conversion ctor: string::string(const char*). ● Sometimes implicit conversion is not desired for single-parameter ctors. ● (E.g. to avoid "surprises" with overloaded functions.) ● Therefor C++ allows conversion ctors to be marked as explicit conversion ctors. class Person { // (members hidden) public: Person(const char* name) { /* pass */ } }; void AcceptsPerson(Person person) { /* pass */ } void AcceptsPerson(Person person) { /* pass */ } class Person { // (members hidden) public: explicit Person(const char* name) { /* pass */ } }; AcceptsPerson("nico"); // Ok! AcceptsPerson("nico"); // Invalid! No implicit conversion! AcceptsPerson(Person("nico")); // Ok! Explicit conversion. ● HandlePerson(Person) and HandlePerson(const Person&) would not be called, if HandlePerson(const char*) existed and HandlePerson("nico") be called. The best match is taken, implicit conversion and temporary copies are avoided at overload resolution.
  • 14. 14 Problems with Reference Parameters ● After the discussion concerning costly copying, let's use references for all UDTsto avoid (deep) copying in future! - But there are problems: – 1. With functions accepting references we could modify the original argument! ● Very often this happens accidentally, here it is shown in a more radical example: – 2. Functions accepting references can't cope w/ objects created by implicit conversions. ● E.g. a const char* can't be implicitly converted into an std::string and passed to an std::string&: ● This yields a compiler message like "Non l-value can't be bound to non-const reference." void PrintToConsole(std::string& text) { std::cout<<text<<std::endl; // Oups! Modified the parameter and the argument! text = "Angela"; } void PrintToConsole(std::string& text) { std::cout<<text<<std::endl; } std::string pamela = "Pamela"; PrintToConsole(pamela); // >Pamela std::cout<<pamela<<std::endl; // >Angela (Oups! The content of pamela has been modified!) // Invalid! Literal const char* can't be passed! PrintToConsole("Pamela"); ● An object created by implicit conversion is a temporary object, and as such it can't be an lvalue, therefor this message happens to appear.
  • 15. 15 Const References ● The discussed problems can be solved with const references (const&). ● const& parameters can not be modified (accidentally), e.g. assigned to. – const std::string& are esp. important as std::string is a mutable string type. – The same is valid for const pointers (e.g. also as parameters) as well. ● const& parameters can accept temporary anonymous conversion copies. – A const char* can be implicitly converted into an std::string and passed to a const std::string&: void PrintToConsole(const std::string& text) { std::cout<<text<<std::endl; // Invalid! Const parameter. text = "Angela"; } void PrintToConsole(const std::string& text) { std::cout<<text<<std::endl; } std::string pamela = "Pamela"; PrintToConsole(pamela); // >Pamela // Fine! Literal const char* can be passed now! PrintToConsole("Pamela"); ● This is a very important fact: const char* have been non-modifiable, but the STL type std::string is mutable! With const std::strings, (and const& thereof) we can get const char*'s safety aspect back. ● Strings in Java and .Net are not mutable. On that platforms string operations create new strings instead of modifying the string on which they have been called.
  • 16. 16 The need for const Member Functions ● Ok! Then let's use const& for all UDTs! - But there are still problems: – We can't call all the member functions via a const&. ● C++ assumes that all member functions potentially modify the target object. – Calling member functions on const& and const pointers is generally not allowed. – Compilers can't predict, whether called member functions modify the object. ● To solve this problem C++ introduces so called const member functions. – Only const member functions can be called on const objects. class Date { // (members hidden) int month; public: int GetMonth() { return month; } }; void PrintMonth(const Date& date) { // Invalid! Can't call non-const member function on const&. std::cout<<date.GetMonth()<<std::endl; } void PrintMonth(const Date* date) { // Invalid! Can't call non-const member function on const pointer. std::cout<<date->GetMonth()<<std::endl; }
  • 17. 17 Implementing const Member Functions ● To make a member function const: just add the const suffix to declaration and definition. ● In the implementation of a const member function – fields can only be read, – only free functions, static member functions and other const member functions can be called. – The const-ness of const member functions is kind of "closed". – std::string provides a set of const member functions. ● Member functions and const/volatile qualifiers (cv-qualifiers): – We can have a const and a non-const overload of a member function in C++. – C++ also allows the definition of volatile and const volatile member functions. ● Non-const, const, volatile and const volatile do overload! class Date { // (members hidden) int month; public: int GetMonth() const { return month; } }; void PrintMonth(const Date& date) { // Fine! Date::GetMonth() is a const member function. std::cout<<date.GetMonth()<<std::endl; } void PrintMonth(const Date* date) { // Fine! Date::GetMonth() is a const member function. std::cout<<date->GetMonth()<<std::endl; } ● What is "volatile"? ● If an object is declared volatile, the C/C++ compiler assumes that its value could change anytime by any thread of execution. - Accessing a volatile variable is interpreted as direct memory read/write w/o caching. ● The cv-qualification needs to be repeated on a non-inline definition, because cv-qualifiers overload. ● There can be no const static member functions.
  • 18. 18 C++ References summarized: Our Rules for References ● C++ references have been introduced to overload operators, because: – they provide an unobtrusive syntax to make using operators intuitively, – they prevent call by value and – const& allow passing temporary objects, so its also good for non-operator functions. ● Important features of C++ references: – They're similar to pointers as call by reference, aliasing and data sharing is concerned. – References can't be uninitialized and they have no notion of "nullity". ● Some widely used industry standards that we're going to adopt as rules: – (+) Primary use const& for UDT parameters, and avoid passing UDTs by value! – (+) Pass fundamental types only by value or pointer, the compiler cares for optimization. – (+) If we need to modify passed objects we should use non-const pointers. – (-) Don't use references to replace pointers only for syntax purposes in order to modify the passed objects! ● If we see the discussed rules hurt, then this is what we call a "code smell". If the code is under our control, we should refactor it to obey these rules and prove the functionality with unit tests. ● UDTs should be passed by const&, if they are not already being passed as pointer.
  • 19. 19 Circumventing const: mutable Fields ● We can't modify the target object (i.e. this) in const member functions. – We can not write a const Date::SetMonth() member function like so: ● Often real life objects need to differentiate logical from physical const-ness. – I.e. an object presents const member functions that need to write some fields. – C++ provides a backdoor: mutable fields can be written in const member functions. class Date { // (members hidden) public: void SetMonth(int month) const { this->month = month; // Invalid! this->month is readonly } // in a const member function. }; class Date { // (members hidden) mutable int monthAccessed; public: int GetMonth() const { ++monthAccessed; // Fine! Mutable fields can be written return month; // in const member functions. } };
  • 20. 20 Cheating const: Casting const-ness away ● After discussing how to avoid copies, implicit conversion andstd::string, we'd better use const std::string& as function parameter type always. – But this also means that passed std::strings can't be modified! ● There is a way to call non-const member functions on const objects! – const-ness can be casted away in C++ with the const_cast operator: ● Casting const-ness away is dangerous! - It's undefined with temporary objects. – Let's never use const_cast, unless we've a very good reason to use it! void Clear(const std::string& name) { name.erase(); // Invalid! Can't call non-const member function on name. } // That makes sense! std::string::erase() can't be a const member function! void ClearConst(const std::string& name) { std::string& nonConstName = const_cast<std::string&>(name); nonConstName.erase(); // Ok! nonConstName is not const! } std::string nico("nico") ClearConst(nico); // Ok! std::cout<<nico<<std::endl; // > // (empty) ClearConst("nico"); // Undefined behaviour! The literal "nico" // is really const and can't be erased! std::cout<<nico<<std::endl; // > // (empty)
  • 21. 21 "Const-incorrectness" ● All fields of a const object are also const, we can only call const member functions on it. ● Assume the UDT Person and the const member function GetName() in (1). ● When we define a const instance of Person, the UDT virtually changes to (2). ● Was all our work for const-ness for good? - Well, our UDT isn't yet const-correct! class Person { // (1) (members hidden) public: char* name; // Only for demo! char* GetName() const { return this->name; } }; const Person nico("nico"); // But here the surprises: // These operations are allowed(!): std::strcpy(nico.name, "joe"); // The memory to which nico.name points to is not const! std::strcpy(nico.GetName(), "jim"); // The memory to which nico.name points to is not const! // - GetName() just returns a pointer. class Person { // (2) (members hidden) public: char* const name; char* GetName() const { return this->name; } }; // We already know this fact: const Person nico("nico"); // This is not allowed: nico.name = 0; // Invalid! // The field nico.name is a const pointer! ● Another way to understand const correctness: const member functions need to be balanced to other const member functions and their return types. Finally, const correct types allow the creation of immutable types in C++. (The support for immutable types is not so good in C#.)
  • 22. 22 Const-correctness ● The just encountered problem is that const-ness is not deep enough! – The const-ness of an object only affects the fields, not the memory the fields refer to. ● This problem is relevant for pointers as well as for references. – const members functions don't shield us from modifiable referred memory! ● To make Person/GetName() const-correct, we'll make the field name private and fix GetName() to return a const char* instead of a char*. – 1. The field name can't be accessed from "outside". – 2. GetName() returns a const char*, it doesn't allow writing memory referenced byname. ● const correct: Generally return const pointers/references from const member function. class Person { // (members hidden) char* name; public: const char* GetName() const { return this->name; } }; const Person nico("nico"); // Now Person is const correct: std::strcpy(nico.name, "joe"); // Invalid! name is private! std::strcpy(nico.GetName(), "jim"); // Invalid! GetName() // returns a const char* that doesn't allow to write the // referred memory.