Effective C++ Guidelines and Implementation Techniques

Const Usage and Member Functions

Proper Const Implementation

Modern compilers enforce const correctness by requiring const member functions to return const references:


class Document {
public:
    const char& getCharAt(std::size_t index) const { return content[index]; }
private:
    char* content;
};

When implementing both const and non-const versions of member functions, implement the const version first and have the non-const version call it:


// Const version
const char& getCharAt(std::size_t index) const { return content[index]; }

// Non-const version
char& getCharAt(std::size_t index) {
    return const_cast<char>(
        static_cast<const document="">(*this).getCharAt(index)
    );
}
</const></char>

Object Initialization and Construction

Member Initialization Lists

Use member initialization lists rather than assignment in constructors. Built-in types default to zero values, and initialization follows declaration order.

Static Object Initialization

For non-local static objects, use local static objects within functions to guarantee proper initialization order:


class Database {
public:
    static Database& instance() {
        static Database db;
        return db;
    }
};

Compiler-Generated Functions and Prevention

Automatic Function Generation

Compilers automatically generate default constructor, copy constructor, and assignment operator if not explicitly defined.

Preventing Copy Operations

C++11 approach using delete keyword:


class NonCopyable {
public:
    NonCopyable(const NonCopyable&) = delete;
    NonCopyable& operator=(const NonCopyable&) = delete;
};

Resource Management and RAII

Smart Pointers

Use unique_ptr instead of deprecated auto_ptr. Use weak_ptr to break circular references in shared_ptr usage.

Resource Management Classes

Provide access to raw resources in resource management classes and define appropriate copying behavior.

Class Design and Interface Guidelines

Member Variable Access

Declare member variables as private to provide implementation flexibility and maintain encapsulation.

Parameter Passing

Prefer pass-by-reference-to-const over pass-by-value for custom types, while using pass-by-value for built-in types, iterators, and function objects.

Return Value Guidelines

Never return references to local variables or temporary objects. Modern compilers detect and warn about this issue.

Inheritance and Polymorphism

Virtual Function Alternatives

Non-virtual interface (NVI) pattern separates public interface from implementation:


class GameCharacter {
public:
    int healthValue() const {
        // Pre-processing
        int result = calculateHealth();
        // Post-processing
        return result;
    }
private:
    virtual int calculateHealth() const { return 100; }
};

Strategy Pattern Implementation

Using function pointers or strategy objects instead of virtual functions:


class HealthCalculator {
public:
    virtual int compute(const GameCharacter&) const = 0;
};

class DefaultHealthCalculator : public HealthCalculator {
public:
    int compute(const GameCharacter&) const override { return 100; }
};

class GameCharacter {
public:
    explicit GameCharacter(HealthCalculator* calculator = nullptr) 
        : healthCalculator(calculator ? calculator : &defaultCalculator) {}
    
    int getHealth() const {
        return healthCalculator->compute(*this);
    }
    
private:
    HealthCalculator* healthCalculator;
    static DefaultHealthCalculator defaultCalculator;
};

Templates and Generic Programming

Template Base Class Name Resolution

When inheriting from template base classes, explicitly qualify base class member access:


template<typename company="">
class LoggingMessageSender : public MessageSender<company> {
public:
    void sendWithLog(const MessageInfo& info) {
        // Method 1: Use this->
        this->transmit(info);
        
        // Method 2: Using declaration
        // using MessageSender<company>::transmit;
        // transmit(info);
        
        // Method 3: Explicit qualification
        // MessageSender<company>::transmit(info);
    }
};
</company></company></company></typename>

Member Function Templates

Use member function templates to accept all compatible types:


template<typename t="">
class SmartPointer {
public:
    template<typename u="">
    SmartPointer(const SmartPointer<u>& other) 
        : ptr(other.get()) {}
        
    T* get() const { return ptr; }
    
private:
    T* ptr;
};
</u></typename></typename>

Traits Classes

Use traits classes for compile-time type information and conditional logic:


template<typename iterator="">
struct iterator_traits {
    typedef typename Iterator::value_type value_type;
};

// Specialization for pointer types
template<typename t="">
struct iterator_traits<t> {
    typedef T value_type;
};
</t></typename></typename>

Advanced Techniques

Pimpl Idiom

Use pointer to implementation to reduce compilation dependencies and hide implementation details.

Copy and Swap

Implement exception-safe assignment using copy and swap technique:


class String {
public:
    String& operator=(const String& other) {
        String temp(other); // Copy
        swap(temp);         // Swap
        return *this;
    }
    
    void swap(String& other) noexcept {
        using std::swap;
        swap(data, other.data);
        swap(size, other.size);
    }
    
private:
    char* data;
    std::size_t size;
};

Template Specialization

Use full and partial template specialization to provide specific implementations for particular types.

Tags: C++ const-correctness RAII smart-pointers Templates

Posted on Mon, 29 Jun 2026 17:43:05 +0000 by yodasan000