Misc Flashcards
How can you allow a member variable to be changed in a const qualified class?
Add “mutable” to declaration of variable.
Or make the member variable a pointer to the data (adheres to bitwise constness)
How can you avoid code duplication bw const and non const versions of the same method?
Call the const version from the non const method by using const_cast and static_cast
Give a few reasons to avoid #define
- Preprocessor removes symbol name so debug is more cryptic
- Doesn’t follow scoping
- can result in multiple copies of value when a const guarantees only one
- use enum if you don’t want the address of the const to be taken
Why use explicit constructors? explicit MyInt(const int x);
To avoid implicit type conversion. Like in: MyInt myInt(3); if (myInt == 3)...
The 3 can’t be implicitly converted to a MyInt if the conductor is declared explicit. Otherwise you could get undefined behavior
Why is an initializer list preferable to assigning values in the constructor?
It’s more efficient and avoids possibly uninitialized members. Constructors without an initializer list will call the default constructors for each member, then assignments my call additional constructors. For built in data types, there could be undefined behavior
What is a translation unit?
What’s the problem with multiple non-local static objects defined in different translation units? What’s the solution?
The source code resulting in a single object file. Usually a cpp file and it’s includes.
If one non-local static object uses another from a different translation unit, it could be undefined based on the order of initialization. The init order can’t be determined by design.
The solution is to wrap a non-local static object in a function - this results in a local static instead, which is guaranteed to be initialized when the fn is called. AKA “Singleton Pattern”
When should you make destructors virtual?
In what situation should you avoid virtual fns altogether?
Only in polymorphic base classes. Without virtual, only the base class destructor is called if you have a reference to the base object (rather than derived)
In derived classes that are not themselves bases of another class. Also in small classes/structs where size is an issue (any virtual fn adds size to an instance bc of vtable pointer)
What’s one reason never to inherit from STL string, containers, and possibly others?
They do not have virtual destructors.
Why should destructors never emit exceptions?
an instance going out of scope might throw, and the client would likely not have a chance to handle it.
If a destructor might throw (bc you must use something that could throw), what are a few options?
Pg 48
- Move the throwable action into a public function that the client may use in a try block. Then have a flag in object that checks to see if it was closed properly - if not, try it in the destructor.
- Perform the try in destructor and either swallow the exception or abort.
How do you make assignment ops exception safe and self-assignment safe? Hint: the answer is not “if (this == &that)”
Pg 55
Order the operations such that if an op throws, the original object is unchanged.
Ex:
{ Obj *old = curr; curr = new Obj() // might throw delete old; // won’t get called if exception return *this }
Can having more branches in the flow control decrease performance of the program?
Pg 56
Yes, bc if there are many possible avenues, instruction prefetching, caching, and pipelining will become less effective.
T/F: a compiler can make a copy operation more efficient in parameter passing compared to a copy in the body of function
Pg 57
True
What’s a good choice for practicing RAII on an object that doesn’t need deletion on release?
Pg 64
A std::shared_ptr with a custom deleter that releases the resource instead of deleting.
What should you do with copy semantics of RAII objects?
P68
In general, disallow copying. But if you need to copy, either do a deep copy or reference counting to prevent multiple releases of the same resource
How can you allow a client to use your RAII class as if it were the raw resource? Ex: my_ptr x(new int(10)); doWork(x) // expects raw int*
Pg71
Provide an implicit conversion function!
operator int*() const
{ return rawResource; }
What’s wrong with this code? Pg76
doWork(shared_ptr(new Obj), process())
C++ allows the compiler to order parameter calls in any order it chooses (for optimization). If new is called first, then process() 2nd and throws an exception, the shared pointer will never be constructed and you have a memory leak despite RAII intentions.
What is the “cross DLL problem” regarding resource allocation/deallocation? What’s one way to prevent it?
If an object is created in one DLL with new, and deleted in another DLL with delete, there can be runtime errors.
Can prevent by using a shared_ptr with custom deleter (carries the deleter with it)
Why is this interface error prone? What’s a good way to make this interface harder to use incorrectly? Pg 80
void Date(int day, int month, int year)
Int for each parameter invites invalid values (30 for month), switched values (Europe does month first) and even negatives.
Fix by using a small struct for each of day, month, and year. (Bring it into the type system)
struct month { month(int x) : val(x) {} static month Jan() { return month(1); } ... } // use methods instead of static vars because of Item 4 - non-local static objects across translation units
What is the slicing problem? (polymorphic error)
How can you prevent it?
Pg 87
When a derived object is passed by VALUE as its base class type. Only the base class portion gets copied and unique qualities lost.
Prevent by passing by reference to const.
When should you have public/protected data members in a class (according to the author)? Why?
Pg97
Never.
Making all members private allows class writer to:
Control access levels,
Enforce class invariants,
Change implementation without breaking client code
And it provides syntactic consistency.
What is Argument Dependent Lookup (ADL), or Koenig Lookup?
Pg 110
For UNQUALIFIED function lookups (ie no “namespaceName::” before the fn name), C++ will prefer functions in the same namespace as the arguments, even if there is a std:: or other version visible in that scope.
That’s why the idiomatic
using std::swap
swap( obj1, obj2 )
…Is used. The using makes std::swap available as a fallback if there is no specialization for the “obj” types. Helpful for template fns where the type could be anything.
When should you provide a custom swap fn?
How should you customize it for your classes?
Pg 112
Only if std::swap would be inefficient for your class (like in pimpl idiom).
- Provide a public swap member fn that efficiently swaps 2 instances of your class. NO THROW
- Also create a non-member swap in the same namespace as your class that calls the member.
- If it’s for a regular class (non template), also specialize std::swap. See item 25
- When calling swap, provide “using std::swap” then call swap without namespace qualification.
How can this code be improved?
string s;
s = someConstString;
Pg 115
Bundle it into one call:
string s(someConstString);
This removes the assignment which isn’t free especially for large objects. It also moves the declaration of s to as late as possible