Skip to content

Modernize C++ code to use C++11+ features #88

@m-marinucci

Description

@m-marinucci

Overview

This issue tracks modernizing the TOL codebase to leverage C++11 and later features for improved safety, performance, and maintainability (split from issue #42).

Scope

Systematically update C++ code to use modern language features while maintaining backward compatibility and ensuring no performance regressions.

Acceptance Criteria

  • Use auto keyword for type deduction where appropriate
  • Replace NULL with nullptr throughout codebase
  • Implement range-based for loops where applicable
  • Use uniform initialization syntax consistently
  • Replace C-style casts with C++ style casts
  • Implement move semantics where beneficial
  • Use override keyword for virtual functions
  • Add final keyword where appropriate

Modernization Areas

1. Type Deduction with auto

Before:

std::vector<std::string>::iterator it = vec.begin();
std::map<int, std::string>::const_iterator cit = map.find(key);

After:

auto it = vec.begin();
auto cit = map.find(key);

Guidelines:

  • Use auto when type is obvious from context
  • Avoid auto when it makes code less readable
  • Use auto* for pointer types when needed for clarity

2. Null Pointer Modernization

Before:

if (ptr \!= NULL) {
    // use ptr
}
char* p = NULL;

After:

if (ptr \!= nullptr) {
    // use ptr
}
char* p = nullptr;

3. Range-Based For Loops

Before:

for (std::vector<int>::iterator it = vec.begin(); it \!= vec.end(); ++it) {
    process(*it);
}

After:

for (const auto& item : vec) {
    process(item);
}

4. Uniform Initialization

Before:

std::vector<int> vec(10, 0);
MyClass obj = MyClass();

After:

std::vector<int> vec{10, 0};  // Be careful: this creates {10, 0}, not 10 zeros
std::vector<int> vec(10, 0);  // Keep this for 10 zeros
MyClass obj{};

5. C++ Style Casts

Before:

int* ptr = (int*)malloc(sizeof(int));
Base* base = (Base*)derived;
const int* cptr = (const int*)ptr;

After:

int* ptr = static_cast<int*>(malloc(sizeof(int)));
Base* base = static_cast<Base*>(derived);
const int* cptr = const_cast<const int*>(ptr);

6. Virtual Function Improvements

Before:

class Derived : public Base {
public:
    virtual void func() { /* implementation */ }
    virtual ~Derived() { }
};

After:

class Derived : public Base {
public:
    void func() override { /* implementation */ }
    ~Derived() override = default;
};

7. Move Semantics (where beneficial)

Before:

class Resource {
    char* data;
public:
    Resource(const Resource& other) {
        // expensive copy
    }
};

After:

class Resource {
    std::unique_ptr<char[]> data;
public:
    Resource(Resource&& other) noexcept = default;
    Resource& operator=(Resource&& other) noexcept = default;
};

Implementation Strategy

Phase 1: Safe Mechanical Changes

  1. Replace NULL with nullptr
  2. Add override keyword to virtual functions
  3. Replace obvious C-style casts with C++ casts
  4. Remove deprecated register keywords

Phase 2: Type System Improvements

  1. Introduce auto in obvious cases
  2. Use uniform initialization for new code
  3. Add range-based for loops where beneficial
  4. Use final keyword for classes not meant to be inherited

Phase 3: Advanced Features (Careful Assessment Required)

  1. Evaluate move semantics opportunities
  2. Consider constexpr for compile-time computations
  3. Use = default and = delete for special members
  4. Consider noexcept specifications

Priority Locations

High Priority Files

  1. tol/bbasic/tol_bfsmem.h - Remove register keywords
  2. Core header files - Apply nullptr and modern casts
  3. Main algorithm files - Consider auto and range-based loops

Medium Priority Files

  1. Grammar and parser files - Modernize where safe
  2. Type implementation files - Consider move semantics
  3. Utility classes - Add override and modern patterns

Testing Strategy

# Comprehensive testing after each modernization phase
make clean
cmake .. -DCMAKE_CXX_STANDARD=11 -DCMAKE_BUILD_TYPE=Debug
make -j$(nproc)
make test

# Test with different C++ standards
cmake .. -DCMAKE_CXX_STANDARD=14
cmake .. -DCMAKE_CXX_STANDARD=17

# Performance regression testing
time make test  # Before modernization
time make test  # After modernization

# Memory usage comparison
valgrind --tool=massif ./build/bin/tolcon --version

Compiler Compatibility

Ensure changes work with:

  • GCC 7+ (full C++14 support)
  • Clang 6+ (full C++14 support)
  • MSVC 2017+ (full C++14 support)

Related Issues

Success Metrics

  • Code compiles cleanly with C++11/14/17 standards
  • No performance regression in benchmarks
  • Improved code readability and maintainability
  • Static analysis tools report fewer issues
  • Modern C++ features used appropriately and consistently

Guidelines for Contributors

  • Modernize incrementally, not all at once
  • Prefer readability over showing off modern features
  • Always test changes thoroughly
  • Document any performance implications
  • Consider maintenance burden of new patterns

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions