C++ 最佳实践
概述
C++最佳实践是经过实践检验的编程技巧和设计原则,能帮助开发者写出更安全、高效、可维护的代码。本章总结了现代C++开发中的核心最佳实践,涵盖内存管理、性能优化、设计模式等方面。
🔒 内存管理最佳实践
RAII原则
cpp
#include <memory>
#include <fstream>
#include <vector>
#include <mutex>
// ✅ RAII - 资源获取即初始化
class FileHandler {
private:
std::unique_ptr<std::FILE, decltype(&std::fclose)> file_;
public:
explicit FileHandler(const std::string& filename)
: file_(std::fopen(filename.c_str(), "r"), &std::fclose) {
if (!file_) {
throw std::runtime_error("Cannot open file: " + filename);
}
}
// 析构函数自动清理资源
~FileHandler() = default; // unique_ptr自动调用deleter
std::string readLine() {
if (!file_) return "";
std::string line;
char buffer[256];
if (std::fgets(buffer, sizeof(buffer), file_.get())) {
line = buffer;
}
return line;
}
};
// ✅ 自定义RAII包装器
class MutexLock {
private:
std::mutex& mutex_;
public:
explicit MutexLock(std::mutex& m) : mutex_(m) {
mutex_.lock();
}
~MutexLock() {
mutex_.unlock();
}
// 禁用拷贝和赋值
MutexLock(const MutexLock&) = delete;
MutexLock& operator=(const MutexLock&) = delete;
};
// 使用示例
void processFile(const std::string& filename) {
try {
FileHandler handler(filename);
std::string line = handler.readLine();
// 文件会在作用域结束时自动关闭
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
}智能指针使用
cpp
#include <memory>
#include <vector>
class Resource {
public:
Resource(int id) : id_(id) {
std::cout << "Resource " << id_ << " created\n";
}
~Resource() {
std::cout << "Resource " << id_ << " destroyed\n";
}
void process() {
std::cout << "Processing resource " << id_ << "\n";
}
private:
int id_;
};
class ResourceManager {
public:
// ✅ 使用unique_ptr表示独占所有权
std::unique_ptr<Resource> createResource(int id) {
return std::make_unique<Resource>(id);
}
// ✅ 使用shared_ptr表示共享所有权
std::shared_ptr<Resource> createSharedResource(int id) {
return std::make_shared<Resource>(id);
}
// ✅ 传递智能指针的最佳实践
void processResource(const std::unique_ptr<Resource>& resource) {
if (resource) {
resource->process();
}
}
void shareResource(std::shared_ptr<Resource> resource) { // 按值传递shared_ptr
shared_resources_.push_back(std::move(resource));
}
// ✅ 返回原始指针进行观察
Resource* findResource(int id) {
for (const auto& resource : shared_resources_) {
if (resource && resource.get()->getId() == id) {
return resource.get();
}
}
return nullptr;
}
private:
std::vector<std::shared_ptr<Resource>> shared_resources_;
};
// ✅ 工厂函数返回智能指针
template<typename T, typename... Args>
std::unique_ptr<T> make_unique_resource(Args&&... args) {
return std::make_unique<T>(std::forward<Args>(args)...);
}
// 使用示例
void demonstrateSmartPointers() {
ResourceManager manager;
// 独占所有权
auto unique_resource = manager.createResource(1);
manager.processResource(unique_resource);
// 共享所有权
auto shared_resource = manager.createSharedResource(2);
manager.shareResource(shared_resource);
// weak_ptr避免循环引用
std::weak_ptr<Resource> weak_ref = shared_resource;
if (auto locked = weak_ref.lock()) {
locked->process();
}
}⚡ 性能优化最佳实践
移动语义和完美转发
cpp
#include <string>
#include <vector>
#include <utility>
class DataContainer {
private:
std::vector<std::string> data_;
std::string name_;
public:
// ✅ 支持移动的构造函数
DataContainer(std::string name, std::vector<std::string> data)
: name_(std::move(name)), data_(std::move(data)) {}
// ✅ 拷贝和移动构造函数
DataContainer(const DataContainer& other)
: name_(other.name_), data_(other.data_) {
std::cout << "Copy constructor called\n";
}
DataContainer(DataContainer&& other) noexcept
: name_(std::move(other.name_)), data_(std::move(other.data_)) {
std::cout << "Move constructor called\n";
}
// ✅ 拷贝和移动赋值运算符
DataContainer& operator=(const DataContainer& other) {
if (this != &other) {
name_ = other.name_;
data_ = other.data_;
}
return *this;
}
DataContainer& operator=(DataContainer&& other) noexcept {
if (this != &other) {
name_ = std::move(other.name_);
data_ = std::move(other.data_);
}
return *this;
}
// ✅ 添加元素的不同方式
void addData(const std::string& item) { // 拷贝版本
data_.push_back(item);
}
void addData(std::string&& item) { // 移动版本
data_.push_back(std::move(item));
}
// ✅ 完美转发版本
template<typename T>
void emplaceData(T&& item) {
data_.emplace_back(std::forward<T>(item));
}
// ✅ 就地构造
template<typename... Args>
void emplaceString(Args&&... args) {
data_.emplace_back(std::forward<Args>(args)...);
}
};
// ✅ 完美转发工厂函数
template<typename T, typename... Args>
auto make_object(Args&&... args) -> std::unique_ptr<T> {
return std::make_unique<T>(std::forward<Args>(args)...);
}
// 使用示例
void demonstrateMoveSematics() {
std::vector<std::string> data{"item1", "item2", "item3"};
// 移动构造
DataContainer container1("container1", std::move(data));
// 拷贝构造
DataContainer container2 = container1;
// 移动赋值
DataContainer container3("temp", {});
container3 = std::move(container1);
// 就地构造
container3.emplaceString(10, 'x'); // 构造10个'x'的字符串
}容器和算法优化
cpp
#include <vector>
#include <unordered_map>
#include <algorithm>
#include <numeric>
class OptimizedContainer {
public:
// ✅ 预分配内存
void addManyItems(size_t count) {
items_.reserve(items_.size() + count); // 避免多次重新分配
for (size_t i = 0; i < count; ++i) {
items_.emplace_back(generateItem(i));
}
}
// ✅ 使用算法而非手写循环
void processItems() {
// 并行处理(C++17)
std::for_each(std::execution::par_unseq,
items_.begin(), items_.end(),
[](auto& item) { item.process(); });
// 条件计数
auto valid_count = std::count_if(items_.begin(), items_.end(),
[](const auto& item) { return item.isValid(); });
// 查找
auto it = std::find_if(items_.begin(), items_.end(),
[](const auto& item) { return item.getId() == target_id_; });
if (it != items_.end()) {
found_item_ = *it;
}
}
// ✅ 范围算法(C++20)
void modernProcessing() {
namespace ranges = std::ranges;
// 过滤和变换
auto valid_ids = items_
| ranges::views::filter([](const auto& item) { return item.isValid(); })
| ranges::views::transform([](const auto& item) { return item.getId(); });
// 排序
ranges::sort(items_, [](const auto& a, const auto& b) {
return a.getPriority() > b.getPriority();
});
}
// ✅ 高效的查找结构
void setupLookup() {
// 使用unordered_map进行快速查找
for (const auto& item : items_) {
id_to_item_[item.getId()] = &item;
}
}
const Item* findById(int id) const {
auto it = id_to_item_.find(id);
return (it != id_to_item_.end()) ? it->second : nullptr;
}
private:
std::vector<Item> items_;
std::unordered_map<int, const Item*> id_to_item_;
int target_id_ = 0;
Item found_item_;
Item generateItem(size_t index) {
return Item{static_cast<int>(index)};
}
};🏗️ 设计最佳实践
SOLID原则应用
cpp
// ✅ 单一职责原则 (Single Responsibility Principle)
class UserValidator {
public:
bool isValidEmail(const std::string& email) const {
return email.find('@') != std::string::npos;
}
bool isValidPassword(const std::string& password) const {
return password.length() >= 8;
}
};
class UserRepository {
public:
virtual ~UserRepository() = default;
virtual bool saveUser(const User& user) = 0;
virtual std::optional<User> findUser(const std::string& email) = 0;
};
class UserService {
private:
std::unique_ptr<UserValidator> validator_;
std::unique_ptr<UserRepository> repository_;
public:
UserService(std::unique_ptr<UserValidator> validator,
std::unique_ptr<UserRepository> repository)
: validator_(std::move(validator))
, repository_(std::move(repository)) {}
bool registerUser(const std::string& email, const std::string& password) {
if (!validator_->isValidEmail(email) ||
!validator_->isValidPassword(password)) {
return false;
}
User user{email, password};
return repository_->saveUser(user);
}
};
// ✅ 开闭原则 (Open/Closed Principle)
class Shape {
public:
virtual ~Shape() = default;
virtual double area() const = 0;
virtual void draw() const = 0;
};
class Circle : public Shape {
private:
double radius_;
public:
explicit Circle(double radius) : radius_(radius) {}
double area() const override {
return 3.14159 * radius_ * radius_;
}
void draw() const override {
std::cout << "Drawing circle with radius " << radius_ << std::endl;
}
};
class ShapeCalculator {
public:
double totalArea(const std::vector<std::unique_ptr<Shape>>& shapes) const {
return std::accumulate(shapes.begin(), shapes.end(), 0.0,
[](double sum, const auto& shape) {
return sum + shape->area();
});
}
};
// ✅ 依赖注入
class DatabaseConfig {
public:
virtual ~DatabaseConfig() = default;
virtual std::string getConnectionString() const = 0;
};
class Database {
private:
std::shared_ptr<DatabaseConfig> config_;
public:
explicit Database(std::shared_ptr<DatabaseConfig> config)
: config_(std::move(config)) {}
bool connect() {
std::string conn_str = config_->getConnectionString();
// 连接逻辑
return true;
}
};异常安全保证
cpp
#include <vector>
#include <memory>
#include <stdexcept>
class ExceptionSafeContainer {
private:
std::vector<std::unique_ptr<Resource>> resources_;
size_t capacity_;
public:
explicit ExceptionSafeContainer(size_t initial_capacity = 10)
: capacity_(initial_capacity) {
resources_.reserve(capacity_);
}
// ✅ 强异常安全保证
void addResource(std::unique_ptr<Resource> resource) {
if (!resource) {
throw std::invalid_argument("Resource cannot be null");
}
// 如果需要扩容,先检查是否可能失败
if (resources_.size() >= capacity_) {
// 创建新的容器,如果失败不会影响原容器
std::vector<std::unique_ptr<Resource>> new_resources;
new_resources.reserve(capacity_ * 2);
// 移动现有资源(不会抛异常)
for (auto& res : resources_) {
new_resources.push_back(std::move(res));
}
// 添加新资源
new_resources.push_back(std::move(resource));
// 原子性更新(不会抛异常)
resources_ = std::move(new_resources);
capacity_ *= 2;
} else {
// 直接添加(可能抛异常,但不会破坏容器状态)
resources_.push_back(std::move(resource));
}
}
// ✅ 基本异常安全保证
void processAllResources() {
size_t processed = 0;
try {
for (auto& resource : resources_) {
if (resource) {
resource->process();
++processed;
}
}
} catch (const std::exception& e) {
// 记录已处理的数量,保证容器仍然有效
std::cerr << "Processed " << processed << " resources before error: "
<< e.what() << std::endl;
throw; // 重新抛出异常
}
}
// ✅ 无抛出保证
size_t size() const noexcept {
return resources_.size();
}
bool empty() const noexcept {
return resources_.empty();
}
void clear() noexcept {
resources_.clear();
}
};
// ✅ RAII + 异常安全的事务类
class Transaction {
private:
bool committed_ = false;
std::function<void()> rollback_action_;
public:
template<typename RollbackFunc>
explicit Transaction(RollbackFunc&& rollback)
: rollback_action_(std::forward<RollbackFunc>(rollback)) {}
~Transaction() {
if (!committed_ && rollback_action_) {
try {
rollback_action_();
} catch (...) {
// 析构函数中不能抛异常
std::cerr << "Error during rollback" << std::endl;
}
}
}
void commit() noexcept {
committed_ = true;
}
Transaction(const Transaction&) = delete;
Transaction& operator=(const Transaction&) = delete;
};🧪 测试驱动开发
可测试代码设计
cpp
#include <gmock/gmock.h>
#include <gtest/gtest.h>
// ✅ 依赖注入使代码可测试
class EmailService {
public:
virtual ~EmailService() = default;
virtual bool sendEmail(const std::string& to,
const std::string& subject,
const std::string& body) = 0;
};
class Logger {
public:
virtual ~Logger() = default;
virtual void log(const std::string& message) = 0;
};
class NotificationService {
private:
std::shared_ptr<EmailService> email_service_;
std::shared_ptr<Logger> logger_;
public:
NotificationService(std::shared_ptr<EmailService> email_service,
std::shared_ptr<Logger> logger)
: email_service_(std::move(email_service))
, logger_(std::move(logger)) {}
bool sendWelcomeEmail(const std::string& user_email) {
logger_->log("Sending welcome email to: " + user_email);
bool success = email_service_->sendEmail(
user_email,
"Welcome!",
"Welcome to our service!"
);
if (success) {
logger_->log("Welcome email sent successfully");
} else {
logger_->log("Failed to send welcome email");
}
return success;
}
};
// Mock对象
class MockEmailService : public EmailService {
public:
MOCK_METHOD(bool, sendEmail,
(const std::string& to, const std::string& subject, const std::string& body),
(override));
};
class MockLogger : public Logger {
public:
MOCK_METHOD(void, log, (const std::string& message), (override));
};
// 测试
class NotificationServiceTest : public ::testing::Test {
protected:
void SetUp() override {
mock_email_service_ = std::make_shared<MockEmailService>();
mock_logger_ = std::make_shared<MockLogger>();
service_ = std::make_unique<NotificationService>(mock_email_service_, mock_logger_);
}
std::shared_ptr<MockEmailService> mock_email_service_;
std::shared_ptr<MockLogger> mock_logger_;
std::unique_ptr<NotificationService> service_;
};
TEST_F(NotificationServiceTest, SendWelcomeEmailSuccess) {
const std::string email = "user@example.com";
EXPECT_CALL(*mock_logger_, log("Sending welcome email to: " + email));
EXPECT_CALL(*mock_email_service_, sendEmail(email, "Welcome!", "Welcome to our service!"))
.WillOnce(::testing::Return(true));
EXPECT_CALL(*mock_logger_, log("Welcome email sent successfully"));
bool result = service_->sendWelcomeEmail(email);
EXPECT_TRUE(result);
}🔧 现代C++特性使用
类型安全和constexpr
cpp
#include <type_traits>
#include <concepts>
// ✅ 强类型包装器
template<typename T, typename Tag>
class StrongType {
private:
T value_;
public:
explicit constexpr StrongType(T value) : value_(std::move(value)) {}
constexpr const T& get() const noexcept { return value_; }
constexpr T& get() noexcept { return value_; }
// 比较运算符
constexpr bool operator==(const StrongType& other) const noexcept {
return value_ == other.value_;
}
constexpr auto operator<=>(const StrongType& other) const noexcept {
return value_ <=> other.value_;
}
};
// 类型别名
using UserId = StrongType<int, struct UserIdTag>;
using ProductId = StrongType<int, struct ProductIdTag>;
using Price = StrongType<double, struct PriceTag>;
// ✅ 概念约束(C++20)
template<typename T>
concept Numeric = std::is_arithmetic_v<T>;
template<typename T>
concept Container = requires(T container) {
typename T::value_type;
typename T::iterator;
container.begin();
container.end();
container.size();
};
// ✅ constexpr函数
constexpr Price calculateTax(Price base_price, double tax_rate) {
return Price{base_price.get() * (1.0 + tax_rate)};
}
// ✅ if constexpr用于模板特化
template<typename T>
void processValue(const T& value) {
if constexpr (std::is_arithmetic_v<T>) {
std::cout << "Processing numeric value: " << value << std::endl;
} else if constexpr (std::is_same_v<T, std::string>) {
std::cout << "Processing string: " << value << std::endl;
} else {
std::cout << "Processing other type" << std::endl;
}
}
// 使用示例
void demonstrateModernCpp() {
UserId user_id{12345};
ProductId product_id{67890};
// 编译时错误:不能比较不同类型
// bool same = (user_id == product_id); // 编译错误
Price base_price{100.0};
constexpr double tax_rate = 0.1;
// constexpr计算
constexpr auto final_price = calculateTax(Price{100.0}, 0.1);
processValue(42);
processValue(std::string{"Hello"});
processValue(user_id);
}总结
核心最佳实践
- RAII: 资源管理的黄金法则
- 智能指针: 自动内存管理
- 移动语义: 性能优化的关键
- 异常安全: 保证程序健壮性
- 依赖注入: 提高代码可测试性
性能最佳实践
- 避免不必要拷贝: 使用引用和移动语义
- 预分配内存: 容器reserve操作
- 算法优于循环: 使用STL算法
- constexpr: 编译时计算
- 缓存友好: 考虑内存访问模式
设计最佳实践
- SOLID原则: 良好的面向对象设计
- 组合优于继承: 灵活的代码结构
- 接口隔离: 小而专一的接口
- 强类型: 编译时类型安全
- 概念约束: 清晰的模板接口
代码质量最佳实践
- TDD: 测试驱动开发
- 代码审查: 团队知识共享
- 静态分析: 工具辅助质量检查
- 文档化: 清晰的代码文档
- 持续重构: 保持代码整洁
现代C++特性
- auto: 类型推导
- 范围for: 简洁的迭代
- lambda: 函数式编程
- 智能指针: 现代内存管理
- 概念: 模板约束(C++20)
避免的反模式
- 裸指针: 除非必要避免使用
- 全局变量: 破坏封装性
- 深度继承: 复杂的类层次
- premature optimization: 过早优化
- 复杂模板: 难以理解和维护
C++最佳实践是经验的结晶,遵循这些实践能显著提升代码质量、性能和可维护性。随着C++标准的发展,最佳实践也在不断演进,保持学习和更新是C++开发者的必修课。