c++ 多年工作经验总结 望笑纳

c++关键概念以及最佳实践

1. 智能指针使用

理论: 智能指针是 RAII (Resource Acquisition Is Initialization) 的一种实现,它们能自动管理动态分配的内存,防止内存泄漏。

示例:

```cpp
#include <memory>

class Resource {
public:
    void doSomething() { /* ... */ }
};

void useResource() {
    // 使用 unique_ptr
    std::unique_ptr<Resource> res = std::make_unique<Resource>();
    res->doSomething();

    // 使用 shared_ptr
    std::shared_ptr<Resource> sharedRes = std::make_shared<Resource>();
    auto anotherRef = sharedRes; // 引用计数增加
}
// 函数结束时,智能指针自动释放资源
```

2. RAII 技术

理论: RAII 确保资源在对象构造时获取,在对象析构时释放,从而防止资源泄漏。

示例:

```cpp
class FileHandler {
    FILE* file;
public:
    FileHandler(const char* filename) {
        file = fopen(filename, "r");
        if (!file) throw std::runtime_error("File open failed");
    }
    ~FileHandler() {
        if (file) fclose(file);
    }
    // ... 文件操作方法
};

void processFile(const char* filename) {
    FileHandler fh(filename);
    // 使用 fh 进行文件操作
} // fh 离开作用域时自动关闭文件
```

3. 移动语义

理论: 移动语义允许资源的高效转移,而不是昂贵的拷贝操作。

示例:

```cpp
class BigObject {
    std::vector<int> data;
public:
    BigObject(std::vector<int>&& vec) : data(std::move(vec)) {}
};

std::vector<int> createVector() {
    std::vector<int> v(10000, 1);
    return v;
}

BigObject obj(createVector()); // 使用移动语义,避免拷贝
```

4. Lambda 表达式

理论: Lambda 表达式提供了一种简洁的方式来定义匿名函数对象。

示例:

```cpp
#include <algorithm>
#include <vector>

std::vector<int> numbers = {1, 2, 3, 4, 5};

// 使用 lambda 表达式进行排序
std::sort(numbers.begin(), numbers.end(), [](int a, int b) {
    return a > b;
});

// 使用 lambda 进行转换
std::transform(numbers.begin(), numbers.end(), numbers.begin(),
               [](int n) { return n * 2; });
```

5. 异常处理

理论: 异常处理提供了一种结构化和统一的错误处理机制。

示例:

```cpp
#include <stdexcept>

double divide(double a, double b) {
    if (b == 0) {
        throw std::runtime_error("Division by zero");
    }
    return a / b;
}

void useDivide() {
    try {
        double result = divide(10, 0);
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }
}
```

6. 模板

理论: 模板允许编写通用代码,可以适用于多种数据类型。

示例:

```cpp
template<typename T>
T max(T a, T b) {
    return (a > b) ? a : b;
}

int main() {
    std::cout << max(3, 7) << std::endl;      // 整数
    std::cout << max(3.14, 2.72) << std::endl; // 浮点数
    std::cout << max(std::string("abc"), std::string("def")) << std::endl; // 字符串
}
```

7. 并发编程

理论: 并发编程允许程序同时执行多个任务,提高效率和响应性。

示例:

```cpp
#include <thread>
#include <mutex>

std::mutex mtx;
int sharedResource = 0;

void incrementResource() {
    std::lock_guard<std::mutex> lock(mtx);
    ++sharedResource;
}

int main() {
    std::thread t1(incrementResource);
    std::thread t2(incrementResource);

    t1.join();
    t2.join();

    std::cout << "Shared Resource: " << sharedResource << std::endl;
}
```

8. 单元测试

理论: 单元测试有助于验证代码的正确性,并使重构和维护更加容易。

示例 (使用 Google Test):

```cpp
#include <gtest/gtest.h>

int add(int a, int b) { return a + b; }

TEST(AddTest, PositiveNumbers) {
    EXPECT_EQ(add(2, 3), 5);
}

TEST(AddTest, NegativeNumbers) {
    EXPECT_EQ(add(-1, -1), -2);
}

int main(int argc, char **argv) {
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
```

高级主题展示了 C++ 的强大和灵活性

9. 右值引用和完美转发

理论: 右值引用允许我们区分左值和右值,从而实现移动语义。完美转发允许函数模板在不损失参数类型信息的情况下转发参数。

示例:

```cpp
#include <utility>

void process(int& i) { std::cout << "左值引用" << std::endl; }
void process(int&& i) { std::cout << "右值引用" << std::endl; }

template<typename T>
void perfectForward(T&& arg) {
    process(std::forward<T>(arg));
}

int main() {
    int x = 10;
    perfectForward(x);  // 输出: 左值引用
    perfectForward(5);  // 输出: 右值引用
}
```

10. 函数对象和 std::function

理论: 函数对象(仿函数)是重载了 operator() 的类。std::function 是一个通用的函数包装器,可以存储、复制和调用任何可调用目标。

示例:

```cpp
#include <functional>

class Multiplier {
public:
    int operator()(int x, int y) const { return x * y; }
};

int add(int x, int y) { return x + y; }

int main() {
    Multiplier mult;
    std::cout << mult(3, 4) << std::endl;  // 输出: 12

    std::function<int(int,int)> func = add;
    std::cout << func(3, 4) << std::endl;  // 输出: 7

    func = mult;
    std::cout << func(3, 4) << std::endl;  // 输出: 12
}
```

11. 变参模板

理论: 变参模板允许模板接受任意数量的模板参数。这对于实现通用的函数或类非常有用。

示例:

```cpp
#include <iostream>

void print() { std::cout << std::endl; }

template<typename T, typename... Args>
void print(T first, Args... args) {
    std::cout << first << " ";
    print(args...);
}

int main() {
    print(1, 2.0, "three", 'f', 5);  // 输出: 1 2 three f 5
}
```

12. SFINAE (Substitution Failure Is Not An Error)

理论: SFINAE 允许在模板实例化过程中,当替换失败时不产生编译错误,而是继续寻找其他可能的重载或特化。

示例:

```cpp
#include <type_traits>

template<typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
void foo(T t) {
    std::cout << "Integer version" << std::endl;
}

template<typename T, typename = std::enable_if_t<!std::is_integral<T>::value>>
void foo(T t) {
    std::cout << "Non-integer version" << std::endl;
}

int main() {
    foo(42);    // 输出: Integer version
    foo(4.2);   // 输出: Non-integer version
}
```

13. 编译时多态性 (CRTP)

理论: CRTP (Curiously Recurring Template Pattern) 是一种实现编译时多态性的技术,允许基类使用派生类的方法。

示例:

```cpp
template<typename Derived>
class Base {
public:
    void interface() {
        static_cast<Derived*>(this)->implementation();
    }
};

class Derived : public Base<Derived> {
public:
    void implementation() {
        std::cout << "Derived implementation" << std::endl;
    }
};

int main() {
    Derived d;
    d.interface();  // 输出: Derived implementation
}
```

14. 内存对齐和数据结构优化

理论: 合理的内存对齐可以提高内存访问效率,减少 CPU 缓存未命中。

示例:

```cpp
#include <cstddef>

struct alignas(64) CacheLineAligned {
    int data[16];
};

struct Inefficient {
    char a;
    double b;
    char c;
};

struct Efficient {
    double b;
    char a;
    char c;
    char padding[6];  // 使结构体大小为 16 字节
};

int main() {
    std::cout << "CacheLineAligned size: " << sizeof(CacheLineAligned) << std::endl;
    std::cout << "Inefficient size: " << sizeof(Inefficient) << std::endl;
    std::cout << "Efficient size: " << sizeof(Efficient) << std::endl;
}
```

15. 协程 (C++20)

理论: 协程提供了一种编写非阻塞、异步代码的方式,使得异步编程更加直观和简单。

示例 (需要 C++20 支持):

```cpp
#include <coroutine>
#include <iostream>

struct Task {
    struct promise_type {
        Task get_return_object() { return {}; }
        std::suspend_never initial_suspend() { return {}; }
        std::suspend_never final_suspend() noexcept { return {}; }
        void return_void() {}
        void unhandled_exception() {}
    };
};

Task simpleCoroutine() {
    std::cout << "Start" << std::endl;
    co_await std::suspend_always{};
    std::cout << "Middle" << std::endl;
    co_await std::suspend_always{};
    std::cout << "End" << std::endl;
}

int main() {
    auto task = simpleCoroutine();
    // 需要实现协程的执行逻辑
}
```

16. 元编程

理论: 元编程允许在编译时生成或操作代码,这可以提高运行时性能并增加代码的灵活性。

示例:

```cpp
#include <type_traits>

// 编译时计算阶乘
template <unsigned N>
struct Factorial {
    static constexpr unsigned value = N * Factorial<N - 1>::value;
};

template <>
struct Factorial<0> {
    static constexpr unsigned value = 1;
};

// 使用 SFINAE 实现编译时类型检查
template <typename T>
struct has_typedef_foobar {
private:
    template <typename C> static char test(typename C::foobar*);
    template <typename C> static int test(...);
public:
    static constexpr bool value = sizeof(test<T>(0)) == sizeof(char);
};

int main() {
    static_assert(Factorial<5>::value == 120, "Factorial calculation error");
    
    struct A { typedef int foobar; };
    struct B { };
    
    static_assert(has_typedef_foobar<A>::value, "A should have typedef foobar");
    static_assert(!has_typedef_foobar<B>::value, "B should not have typedef foobar");
}
```

17. 策略模式和策略类

理论: 策略模式允许在运行时选择算法,而策略类则是在编译时选择。这提供了灵活性和性能之间的权衡。

示例:

```cpp
#include <iostream>
#include <memory>

// 运行时策略模式
class Strategy {
public:
    virtual void execute() = 0;
    virtual ~Strategy() = default;
};

class ConcreteStrategyA : public Strategy {
public:
    void execute() override { std::cout << "Executing strategy A" << std::endl; }
};

class ConcreteStrategyB : public Strategy {
public:
    void execute() override { std::cout << "Executing strategy B" << std::endl; }
};

class Context {
    std::unique_ptr<Strategy> strategy;
public:
    void setStrategy(std::unique_ptr<Strategy> s) { strategy = std::move(s); }
    void executeStrategy() { strategy->execute(); }
};

// 编译时策略类
template <typename StrategyT>
class CompileTimeContext {
    StrategyT strategy;
public:
    void executeStrategy() { strategy.execute(); }
};

struct CompileTimeStrategyA {
    void execute() { std::cout << "Compile-time strategy A" << std::endl; }
};

int main() {
    // 运行时策略
    Context context;
    context.setStrategy(std::make_unique<ConcreteStrategyA>());
    context.executeStrategy();
    context.setStrategy(std::make_unique<ConcreteStrategyB>());
    context.executeStrategy();

    // 编译时策略
    CompileTimeContext<CompileTimeStrategyA> ctContext;
    ctContext.executeStrategy();
}
```

18. PIMPL (Pointer to Implementation) 惯用法

理论: PIMPL 通过将实现细节隐藏在指针后面,减少编译依赖,提高编译速度,并提供更好的 ABI 稳定性。

示例:

```cpp
// In header file
class Widget {
public:
    Widget();
    ~Widget();
    void doSomething();

private:
    class Impl;
    std::unique_ptr<Impl> pImpl;
};

// In source file
#include "widget.h"
#include <iostream>

class Widget::Impl {
public:
    void doSomething() { std::cout << "Doing something" << std::endl; }
};

Widget::Widget() : pImpl(std::make_unique<Impl>()) {}
Widget::~Widget() = default;

void Widget::doSomething() {
    pImpl->doSomething();
}
```

19. 编译时断言和静态检查

理论: 编译时断言和静态检查可以在编译阶段捕获错误,提高代码的安全性和正确性。

示例:

```cpp
#include <type_traits>

template <typename T>
void processValue(T value) {
    static_assert(std::is_integral_v<T>, "T must be an integral type");
    // ... 处理整数值
}

template <typename T, std::size_t Size>
class FixedBuffer {
    T data[Size];
public:
    static_assert(Size > 0, "Buffer size must be greater than zero");
    // ... 缓冲区实现
};

int main() {
    processValue(42);  // OK
    // processValue(3.14);  // 编译错误

    FixedBuffer<int, 10> buffer;  // OK
    // FixedBuffer<double, 0> invalidBuffer;  // 编译错误
}
```

20. 优化技巧

理论: 了解一些常见的优化技巧可以帮助你编写更高效的代码。

示例:

```cpp
#include <vector>
#include <algorithm>

// 1. 使用 reserve 预分配内存
void efficientVectorUsage() {
    std::vector<int> vec;
    vec.reserve(1000);  // 预分配空间,避免多次重新分配
    for (int i = 0; i < 1000; ++i) {
        vec.push_back(i);
    }
}

// 2. 使用 emplace_back 代替 push_back
struct ExpensiveToCopy {
    ExpensiveToCopy(int n) : data(n) {}
    std::vector<int> data;
};

void efficientInsertion() {
    std::vector<ExpensiveToCopy> vec;
    vec.emplace_back(1000);  // 直接在容器中构造对象
}

// 3. 避免不必要的拷贝
std::vector<int> getVector() {
    return std::vector<int>{1, 2, 3, 4, 5};
}

void avoidUnnecessaryCopy() {
    auto vec = getVector();  // 使用移动语义,避免拷贝
}

// 4. 使用 std::array 代替固定大小的 C 风格数组
#include <array>

void useStdArray() {
    std::array<int, 5> arr = {1, 2, 3, 4, 5};  // 栈上分配,性能好
    std::sort(arr.begin(), arr.end());
}

int main() {
    efficientVectorUsage();
    efficientInsertion();
    avoidUnnecessaryCopy();
    useStdArray();
}
```

非常好,让我们继续探讨更多 C++ 的高级主题和最佳实践:

21. 并发编程

理论: C++11 引入了线程支持库,使得并发编程变得更加容易和安全。

示例:

```cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <future>

std::mutex mtx;

void printNumbers(int id) {
    for (int i = 0; i < 5; ++i) {
        std::lock_guard<std::mutex> lock(mtx);
        std::cout << "Thread " << id << ": " << i << std::endl;
    }
}

int computeSum(int a, int b) {
    return a + b;
}

int main() {
    // 使用 std::thread
    std::thread t1(printNumbers, 1);
    std::thread t2(printNumbers, 2);
    t1.join();
    t2.join();

    // 使用 std::async 和 std::future
    auto future = std::async(std::launch::async, computeSum, 10, 20);
    std::cout << "Sum: " << future.get() << std::endl;

    return 0;
}
```

22. 内存模型和原子操作

理论: C++11 引入了内存模型,定义了多线程程序中内存访问的行为。原子操作提供了无锁编程的基础。

示例:

```cpp
#include <atomic>
#include <thread>
#include <iostream>

std::atomic<int> counter(0);

void increment() {
    for (int i = 0; i < 1000; ++i) {
        counter.fetch_add(1, std::memory_order_relaxed);
    }
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);
    t1.join();
    t2.join();
    std::cout << "Final counter value: " << counter << std::endl;
    return 0;
}
```

23. 模板元编程进阶

理论: 模板元编程允许在编译时执行复杂的计算和类型操作。

示例:

```cpp
#include <iostream>
#include <type_traits>

// 编译时 if 语句
template<bool Condition, typename TrueType, typename FalseType>
struct if_;

template<typename TrueType, typename FalseType>
struct if_<true, TrueType, FalseType> {
    using type = TrueType;
};

template<typename TrueType, typename FalseType>
struct if_<false, TrueType, FalseType> {
    using type = FalseType;
};

// 编译时循环(求幂)
template<int Base, unsigned Exponent>
struct Power {
    static constexpr int value = Base * Power<Base, Exponent - 1>::value;
};

template<int Base>
struct Power<Base, 0> {
    static constexpr int value = 1;
};

int main() {
    using T = if_<std::is_integral<int>::value, int, double>::type;
    std::cout << "Type: " << typeid(T).name() << std::endl;

    constexpr int result = Power<2, 10>::value;
    std::cout << "2^10 = " << result << std::endl;

    return 0;
}
```

24. 智能指针的自定义删除器

理论: 自定义删除器允许你控制智能指针如何释放资源,特别适用于非标准资源管理。

示例:

```cpp
#include <memory>
#include <iostream>

struct FileDeleter {
    void operator()(FILE* file) {
        if (file) {
            fclose(file);
            std::cout << "File closed" << std::endl;
        }
    }
};

int main() {
    {
        std::unique_ptr<FILE, FileDeleter> file(fopen("test.txt", "w"));
        if (file) {
            fputs("Hello, World!", file.get());
        }
    } // 文件在这里自动关闭

    return 0;
}
```

25. 编译时多态性与类型擦除

理论: 编译时多态性通过模板实现,而类型擦除允许在运行时处理不同类型,同时保持类型安全。

示例:

```cpp
#include <memory>
#include <iostream>
#include <vector>

// 编译时多态性
template <typename T>
void print(const T& value) {
    std::cout << value << std::endl;
}

// 类型擦除
class Any {
    struct Concept {
        virtual ~Concept() = default;
        virtual void print() const = 0;
    };
    
    template <typename T>
    struct Model : Concept {
        T value;
        Model(const T& v) : value(v) {}
        void print() const override {
            std::cout << value << std::endl;
        }
    };

    std::unique_ptr<Concept> ptr;

public:
    template <typename T>
    Any(const T& value) : ptr(std::make_unique<Model<T>>(value)) {}

    void print() const {
        ptr->print();
    }
};

int main() {
    // 编译时多态性
    print(42);
    print("Hello");

    // 类型擦除
    std::vector<Any> vec = {42, 3.14, "World"};
    for (const auto& item : vec) {
        item.print();
    }

    return 0;
}
```

26. 协程的高级用法 (C++20)

理论: 协程提供了一种编写异步代码的新方式,可以简化复杂的异步操作。

示例:

```cpp
#include <coroutine>
#include <iostream>
#include <thread>
#include <chrono>

struct Task {
    struct promise_type {
        Task get_return_object() { return {}; }
        std::suspend_never initial_suspend() { return {}; }
        std::suspend_never final_suspend() noexcept { return {}; }
        void return_void() {}
        void unhandled_exception() {}
    };
};

struct Awaiter {
    bool await_ready() { return false; }
    void await_suspend(std::coroutine_handle<> h) {
        std::thread([h] {
            std::this_thread::sleep_for(std::chrono::seconds(1));
            h.resume();
        }).detach();
    }
    void await_resume() {}
};

Task asyncOperation() {
    std::cout << "Start" << std::endl;
    co_await Awaiter{};
    std::cout << "Middle" << std::endl;
    co_await Awaiter{};
    std::cout << "End" << std::endl;
}

int main() {
    asyncOperation();
    std::this_thread::sleep_for(std::chrono::seconds(3));
    return 0;
}
```

设计模式和常出错误点

设计模式:

1. 单例模式

理论:确保一个类只有一个实例,并提供一个全局访问点。

示例:

```cpp
class Singleton {
private:
    static Singleton* instance;
    Singleton() = default;

public:
    static Singleton* getInstance() {
        if (instance == nullptr) {
            instance = new Singleton();
        }
        return instance;
    }

    // 删除复制构造函数和赋值运算符
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
};

Singleton* Singleton::instance = nullptr;
```

注意:这个实现不是线程安全的。为了线程安全,你可能需要使用双重检查锁定或 Meyer's Singleton。

2. 观察者模式

理论:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。

示例:

```cpp
#include <vector>
#include <algorithm>

class Observer {
public:
    virtual void update(int value) = 0;
};

class Subject {
private:
    std::vector<Observer*> observers;
    int state;

public:
    void attach(Observer* obs) {
        observers.push_back(obs);
    }

    void detach(Observer* obs) {
        observers.erase(std::remove(observers.begin(), observers.end(), obs), observers.end());
    }

    void setState(int s) {
        state = s;
        notify();
    }

    void notify() {
        for (auto obs : observers) {
            obs->update(state);
        }
    }
};
```

3. 工厂方法模式

理论:定义一个用于创建对象的接口,让子类决定实例化哪一个类。

示例:

```cpp
class Product {
public:
    virtual void use() = 0;
};

class ConcreteProductA : public Product {
public:
    void use() override {
        std::cout << "Using Product A" << std::endl;
    }
};

class ConcreteProductB : public Product {
public:
    void use() override {
        std::cout << "Using Product B" << std::endl;
    }
};

class Creator {
public:
    virtual Product* createProduct() = 0;
};

class ConcreteCreatorA : public Creator {
public:
    Product* createProduct() override {
        return new ConcreteProductA();
    }
};

class ConcreteCreatorB : public Creator {
public:
    Product* createProduct() override {
        return new ConcreteProductB();
    }
};
```

容易出错的实例:

1. 内存泄漏

```cpp
void memoryLeak() {
    int* ptr = new int(5);
    // 忘记 delete ptr;
}
```

解决方案:使用智能指针,如 std::unique_ptr 或 std::shared_ptr。

2. 悬挂指针

```cpp
int* dangling_pointer() {
    int x = 5;
    return &x;  // 返回局部变量的地址
}
```

解决方案:不要返回局部变量的地址。如果需要,考虑使用堆内存或智能指针。

3. 缓冲区溢出

```cpp
void buffer_overflow() {
    char buffer[5];
    strcpy(buffer, "This is too long");  // 溢出
}
```

解决方案:使用安全的字符串函数如 strncpy,或者使用 std::string。

4. 线程不安全的单例

```cpp
Singleton* Singleton::getInstance() {
    if (instance == nullptr) {
        instance = new Singleton();  // 非线程安全
    }
    return instance;
}
```

解决方案:使用双重检查锁定或 Meyer's Singleton。

5. 忘记虚析构函数

```cpp
class Base {
public:
    ~Base() { }  // 应该是虚析构函数
};

class Derived : public Base {
public:
    ~Derived() { }
};
```

解决方案:将基类的析构函数声明为虚函数。

6. 拷贝构造函数和赋值运算符

```cpp
class Resource {
    char* buffer;
public:
    Resource(size_t size) : buffer(new char[size]) { }
    ~Resource() { delete[] buffer; }
    // 没有定义拷贝构造函数和赋值运算符
};
```

解决方案:遵循 Rule of Three/Five/Zero。

7. 循环依赖

```cpp
class A;
class B {
public:
    std::shared_ptr<A> a;
};
class A {
public:
    std::shared_ptr<B> b;
};
```

解决方案:使用 std::weak_ptr 打破循环引用。

8. 未检查的动态类型转换

```cpp
Base* b = new Derived();
Derived* d = dynamic_cast<Derived*>(b);
d->derivedFunction();  // 如果转换失败,d 可能是 nullptr
```

解决方案:总是检查 dynamic_cast 的结果。

好的,让我们继续探讨更多的设计模式和常见的C++编程陷阱:

设计模式:

4. 策略模式

理论:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。

示例:

```cpp
class Strategy {
public:
    virtual int doOperation(int num1, int num2) = 0;
};

class OperationAdd : public Strategy {
public:
    int doOperation(int num1, int num2) override {
        return num1 + num2;
    }
};

class OperationSubtract : public Strategy {
public:
    int doOperation(int num1, int num2) override {
        return num1 - num2;
    }
};

class Context {
private:
    Strategy* strategy;
public:
    Context(Strategy* strategy) : strategy(strategy) {}
    int executeStrategy(int num1, int num2) {
        return strategy->doOperation(num1, num2);
    }
};
```

5. 装饰器模式

理论:动态地给一个对象添加一些额外的职责。

示例:

```cpp
class Component {
public:
    virtual std::string operation() = 0;
};

class ConcreteComponent : public Component {
public:
    std::string operation() override {
        return "ConcreteComponent";
    }
};

class Decorator : public Component {
protected:
    Component* component;
public:
    Decorator(Component* c) : component(c) {}
    std::string operation() override {
        return component->operation();
    }
};

class ConcreteDecoratorA : public Decorator {
public:
    ConcreteDecoratorA(Component* c) : Decorator(c) {}
    std::string operation() override {
        return "ConcreteDecoratorA(" + Decorator::operation() + ")";
    }
};
```

6. 适配器模式

理论:将一个类的接口转换成客户希望的另外一个接口。

示例:

```cpp
class Target {
public:
    virtual void request() = 0;
};

class Adaptee {
public:
    void specificRequest() {
        std::cout << "Specific request" << std::endl;
    }
};

class Adapter : public Target {
private:
    Adaptee* adaptee;
public:
    Adapter(Adaptee* a) : adaptee(a) {}
    void request() override {
        adaptee->specificRequest();
    }
};
```

更多容易出错的实例:

9. 对象切片

```cpp
class Base {
public:
    virtual void foo() { std::cout << "Base::foo()" << std::endl; }
};

class Derived : public Base {
public:
    void foo() override { std::cout << "Derived::foo()" << std::endl; }
};

void function(Base b) {  // 参数按值传递,导致对象切片
    b.foo();
}

int main() {
    Derived d;
    function(d);  // 输出 "Base::foo()"
    return 0;
}
```

解决方案:使用引用或指针传递对象。

10. 资源管理错误

```cpp
class ResourceManager {
    int* resource;
public:
    ResourceManager() : resource(new int[100]) {}
    ~ResourceManager() { delete[] resource; }
    ResourceManager(const ResourceManager& other) : resource(new int[100]) {
        std::copy(other.resource, other.resource + 100, resource);
    }
    // 没有定义赋值运算符,可能导致资源泄漏或重复删除
};
```

解决方案:遵循 RAII 原则,实现正确的拷贝构造函数和赋值运算符,或使用智能指针。

11. 误用 std::move

```cpp
std::string str = "Hello";
std::vector<std::string> vec;
vec.push_back(std::move(str));
std::cout << str;  // str 现在可能是空的
```

解决方案:只在确实需要移动语义时使用 std::move,并且在移动后不要再使用原对象。

12. 忽视移动语义

```cpp
class BigObject {
    std::vector<int> data;
public:
    BigObject(std::vector<int> d) : data(d) {}  // 复制构造,效率低
};
```

解决方案:使用移动语义提高效率:

```cpp
BigObject(std::vector<int>&& d) : data(std::move(d)) {}
```

13. 误用 auto

```cpp
std::vector<bool> vec = {true, false, true};
auto item = vec[0];  // item 不是 bool,而是 std::vector<bool>::reference
```

解决方案:明确指定类型,或者使用 decltype(auto)。

14. 循环引用的智能指针

```cpp
struct Node {
    std::shared_ptr<Node> next;
};

void createCycle() {
    auto node1 = std::make_shared<Node>();
    auto node2 = std::make_shared<Node>();
    node1->next = node2;
    node2->next = node1;  // 创建了循环引用
}
```

解决方案:使用 std::weak_ptr 打破循环。

15. 忽视异常安全

```cpp
class UnsafeClass {
    Resource* res1;
    Resource* res2;
public:
    UnsafeClass() {
        res1 = new Resource();  // 如果这里抛出异常,res2 不会被分配,也不会被删除
        res2 = new Resource();
    }
    ~UnsafeClass() {
        delete res1;
        delete res2;
    }
};
```

解决方案:使用智能指针和 RAII,或实现异常安全的构造函数。

16. 误用列表初始化

```cpp
std::vector<int> vec{10, 5};  // 创建包含 10 和 5 的 vector
std::vector<int> vec2(10, 5);  // 创建包含 10 个 5 的 vector
```

好的,让我们继续探讨更多的设计模式和C++编程中的陷阱:

设计模式:

7. 命令模式

理论:将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。

示例:

```cpp
class Command {
public:
    virtual void execute() = 0;
};

class Light {
public:
    void turnOn() { std::cout << "Light is on" << std::endl; }
    void turnOff() { std::cout << "Light is off" << std::endl; }
};

class LightOnCommand : public Command {
private:
    Light* light;
public:
    LightOnCommand(Light* l) : light(l) {}
    void execute() override { light->turnOn(); }
};

class RemoteControl {
private:
    Command* command;
public:
    void setCommand(Command* cmd) { command = cmd; }
    void pressButton() { command->execute(); }
};
```

8. 迭代器模式

理论:提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。

示例:

```cpp
template <typename T>
class Iterator {
public:
    virtual T next() = 0;
    virtual bool hasNext() = 0;
};

template <typename T>
class Container {
public:
    virtual Iterator<T>* createIterator() = 0;
};

template <typename T>
class ConcreteContainer : public Container<T> {
private:
    std::vector<T> data;
public:
    void add(T item) { data.push_back(item); }
    
    class ConcreteIterator : public Iterator<T> {
    private:
        ConcreteContainer* container;
        int index;
    public:
        ConcreteIterator(ConcreteContainer* c) : container(c), index(0) {}
        T next() override { return container->data[index++]; }
        bool hasNext() override { return index < container->data.size(); }
    };
    
    Iterator<T>* createIterator() override { return new ConcreteIterator(this); }
};
```

9. 模板方法模式

理论:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。

示例:

```cpp
class AbstractClass {
public:
    void templateMethod() {
        step1();
        step2();
        step3();
    }
protected:
    virtual void step1() = 0;
    virtual void step2() = 0;
    virtual void step3() { std::cout << "Default step3" << std::endl; }
};

class ConcreteClass : public AbstractClass {
protected:
    void step1() override { std::cout << "ConcreteClass step1" << std::endl; }
    void step2() override { std::cout << "ConcreteClass step2" << std::endl; }
};
```

更多容易出错的实例:

17. 误用 std::unique_ptr 的删除器

```cpp
void incorrectDeleter() {
    std::unique_ptr<int[]> arr(new int[10]);  // 正确
    std::unique_ptr<int> ptr(new int[10]);    // 错误:会导致内存泄漏
}
```

解决方案:对于数组,使用 std::unique_ptr<T[]> 或 std::vector。

18. 忽视const正确性

```cpp
class Widget {
    int data;
public:
    int getData() { return data; }  // 应该是 const 成员函数
};

void processWidget(const Widget& w) {
    int val = w.getData();  // 编译错误
}
```

解决方案:合理使用 const 关键字,尤其是成员函数。

19. 误用静态初始化顺序

```cpp
// file1.cpp
extern SomeClass& getGlobal();
SomeClass& global = getGlobal();

// file2.cpp
SomeClass& getGlobal() {
    static SomeClass instance;
    return instance;
}
```

这可能导致静态初始化顺序问题。

解决方案:使用局部静态对象或单例模式。

20. 忽视移动语义导致的性能问题

```cpp
std::vector<std::string> getStrings() {
    std::vector<std::string> result;
    // ... 填充 result
    return result;  // C++11之前会导致复制,C++11后编译器可能会优化
}

std::vector<std::string> strings = getStrings();  // 可能的不必要复制
```

解决方案:使用移动语义和右值引用。

21. 误用 std::bind

```cpp
auto f = std::bind(std::less<int>(), std::placeholders::_1, 42);
std::vector<int> v = {1, 2, 3, 4, 5};
auto it = std::find_if(v.begin(), v.end(), f);
```

这可能导致性能问题,因为 std::bind 可能会阻止内联。

解决方案:使用 lambda 表达式代替 std::bind。

22. 忽视对齐要求

```cpp
struct Unaligned {
    char c;
    double d;
    int i;
};  // 可能导致性能问题或在某些平台上出错

struct Aligned {
    double d;
    int i;
    char c;
};  // 通常更有效率
```

解决方案:注意结构体成员的顺序,或使用对齐说明符。

23. 线程安全问题

```cpp
class ThreadUnsafe {
    static int counter;
public:
    static void increment() { ++counter; }  // 非线程安全
};
```

解决方案:使用互斥锁、原子操作或其他同步机制。

24. 忽视生命周期问题

```cpp
class Manager {
    std::vector<Observer*> observers;
public:
    void addObserver(Observer* obs) { observers.push_back(obs); }
    void notify() {
        for (auto obs : observers) {
            obs->update();  // 如果某个观察者已被删除,这里可能会崩溃
        }
    }
};
```

重要的是要记住,没有一种模式或技术是万能的。每种模式和技术都有其适用的场景和限制。良好的软件设计需要深入理解问题域,并根据具体情况选择合适的解决方案。

同时,持续学习和实践是提高C++编程技能的关键。跟踪语言的新特性、参与开源项目、阅读高质量的代码库,都是提升技能的有效方法。最后,不要忘记使用现代C++工具,如静态分析器、代码格式化工具等,它们可以帮助你更早地发现潜在问题。
 

  • 12
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值