Resource Management, Notes(3), Effective C++
Resource Management
(I read a Chinese version of the book, any translation problem plz point out.
Use objects to manage resources
Priciples
- put into managing object when acquired resources
(Resource Acquistion Is Initialization; RAII). - managing object uses destructor to ensure the resources is released.
- put into managing object when acquired resources
Methods
- auto_ptr
once be assigned, the right side one is null.
so the feature of abnormal assignment operator makes that it can’t be put into containers. - referencing-counting smart pointer (RCSP)
it can’t break cycles of references.
it seems they’re in the “used” status when 2 unused objects point to each other.
- auto_ptr
Think carefully about copying behavior in resource-managing classes
- create a class to do this.
- no copying. ->
=delete or inherit from uncopyable
- reference-count in the low-level resources (shared_ptr).
class Lock { public: explicit Lock(Mutex* pm): mutexPtr(pm, unlock) { lock(mutexPtr.get()); } } private: std::shared_ptr<Mutex> mutexPtr; };
- deep copying.
copy wrapped resources when copying the resource-managing object. - transfer the ownership of low-level resources (auto_pr).
Provide access to raw resources in resource-managing classes
Sometimes we need to provide compatibility to C APIs.
- provide a
get()
to access the raw pointer, safer.
```cpp
// C APIs.
FontHandle getFont();
void releaseFont(FontHandle fh);
Class Font {
public:
explicit Font(FontHandle fh): f(fh) {}
~Font() { releaseFont(f); }
// …
FontHandle get() const { return f; }
// …
private:
FontHandle f; // Raw font resources
};
* provide implicit conversion function may offer convenience to customers. but the opportunities of unexpected error is increased.
```cpp
class Font {
public:
// ...
operator FontHandle() const { return f; }
// ..
}
Font f1(getFont());
// It is intended to copy a Font object
// but f1 is copied after it is implicitly conversed to FontHandle
FontHandle f2 = f1;
- no contradiction with encapsulation, just to ensure resource releasing.
Use the same form in corresponding uses of new and delete
new->delete
new[]->delete[]
- Tips:
use containers to reduce the risk misusingdelete
when releasing memory of typedefined array.typedef std::string stringArray[4]; std::string* pal = new stringArray; delete pal; // Undefined Behavior delete pal[]; // Good
Stored newed objects in smart pointers in standalone statements
- look at the code below:
```cpp
int priority();
void processWidget(std::shared_ptrpw, int priority);
processWidget(std::shared_ptr
* it is free for the compiler to reorder the operations inside one statement, what if in this order:
`new Widget -> priority() -> shared_ptr`
* once `priority()` throws, the newed pointer will be lost and memory leak may happen.
* the compiler can't reorder the operations between statements, so
the code below avoids the risk above.
```cpp
std::shared_ptr<Widget> pw(new Widget);
processWidget(pw, priority());