实现string类

 

#pragma once

#include <cstddef>
#include <cstring>
#include <algorithm>
#include <stdexcept>

// namespace M {
class string {
public:
    static const size_t s_min_capacity;
private:
    char* data_;        // 字符串数据
    size_t size_;       // 字符串长度
    size_t capacity_;   // 容量

    // 重新分配内存的辅助函数
    void realloc_data(size_t new_cap) {
        new_cap = std::max(new_cap, s_min_capacity);
        char* new_data = new char[new_cap + 1];
        if (size_ > 0) {
            std::memcpy(new_data, data_, size_);
        }
        new_data[size_] = '\0';
        delete[] data_;
        data_ = new_data;
        capacity_ = new_cap;  // capacity_存储用户数据容量
    }

public:
    // 默认构造函数
    string() : size_(0), capacity_(s_min_capacity) {
        data_ = new char[capacity_ + 1];
        data_[0] = '\0';
    }

    // 从C风格字符串构造
    string(const char* str) {
        if (!str) {
            throw std::invalid_argument("null pointer");
        }
        size_ = std::strlen(str);
        capacity_ = std::max(size_, s_min_capacity);
        data_ = new char[capacity_ + 1];
        std::memcpy(data_, str, size_ + 1);
    }

    // 二进制安全的构造函数
    string(const void* data, size_t len) {
        if (!data) {
            throw std::invalid_argument("null pointer");
        }
        size_ = len;
        capacity_ = std::max(len, s_min_capacity);
        data_ = new char[capacity_ + 1];
        std::memcpy(data_, data, len);
        data_[len] = '\0';
    }

    // 拷贝构造函数
    string(const string& other) : size_(other.size_), capacity_(other.capacity_) {
        data_ = new char[capacity_ + 1];
        std::memcpy(data_, other.data_, size_ + 1);
    }

    // 移动构造函数
    string(string&& other) noexcept 
        : data_(other.data_)
        , size_(other.size_)
        , capacity_(other.capacity_) {
        other.data_ = nullptr;
        other.size_ = 0;
        other.capacity_ = 0;
    }

    // 析构函数
    ~string() {
        delete[] data_;
    }

    // 拷贝赋值运算符
    string& operator=(const string& other) {
        if (this != &other) {
            char* new_data = new char[other.capacity_ + 1];
            std::memcpy(new_data, other.data_, other.size_ + 1);
            delete[] data_;
            data_ = new_data;
            size_ = other.size_;
            capacity_ = other.capacity_;
        }
        return *this;
    }

    // 移动赋值运算符
    string& operator=(string&& other) noexcept {
        if (this != &other) {
            delete[] data_;
            data_ = other.data_;
            size_ = other.size_;
            capacity_ = other.capacity_;
            other.data_ = nullptr;
            other.size_ = 0;
            other.capacity_ = 0;
        }
        return *this;
    }

    // 预分配内存
    void reserve(size_t new_cap) {
        if (new_cap > capacity_) {
            realloc_data(new_cap);
        }
    }

    // 释放多余内存
    void shrink_to_fit() {
        if (capacity_ > size_) {
            realloc_data(size_);
        }
    }

    // append 函数
    string& append(const char* str, size_t len) {
        if (!str) throw std::invalid_argument("null pointer");
        if (size_ + len > capacity_) {
            reserve((size_ + len) * 2);
        }
        std::memcpy(data_ + size_, str, len);
        size_ += len;
        data_[size_] = '\0';
        return *this;
    }

    string& append(const char* str) {
        if (!str) throw std::invalid_argument("null pointer");
        return append(str, std::strlen(str));
    }

    // 获取数据
    const char* c_str() const noexcept { return data_; }
    const char* data() const noexcept { return data_; }
    size_t size() const noexcept { return size_; }
    size_t capacity() const noexcept { return capacity_; }
    bool empty() const noexcept { return size_ == 0; }
};
// } // namespace M
const size_t string::s_min_capacity = 15;
View Code

 

测试:

#include <cassert>
#include <iostream>
#include <cstring>
#include "string.h"

// 用于测试的辅助函数
#define TEST_CASE(name) \
    do { \
        std::cout << "Running test case: " << #name << "... "; \
        test_##name(); \
        std::cout << "PASSED" << std::endl; \
    } while (0)

// 测试构造函数
void test_constructors() {
    // 默认构造
    string s1;
    assert(s1.empty());
    assert(s1.size() == 0);
    assert(s1.capacity() == 15);
    assert(s1.c_str()[0] == '\0');

    // C风格字符串构造
    string s2("hello");
    assert(s2.size() == 5);
    assert(s2.capacity() >= 5);
    assert(strcmp(s2.c_str(), "hello") == 0);

    // 二进制安全构造
    char data[] = {'H', 'e', 'l', 'l', 'o', '\0', 'W', 'o', 'r', 'l', 'd'};
    string s3(data, 11);
    assert(s3.size() == 11);
    assert(memcmp(s3.data(), data, 11) == 0);

    // nullptr 检查
    try {
        string s4(nullptr);
        assert(false);  // 不应该到达这里
    } catch (const std::invalid_argument&) {
        // 预期的异常
    }
}

// 测试拷贝操作
void test_copy_operations() {
    string s1("hello");
    
    // 拷贝构造
    string s2(s1);
    assert(strcmp(s2.c_str(), "hello") == 0);
    assert(s1.c_str() != s2.c_str());  // 深拷贝检查
    
    // 拷贝赋值
    string s3;
    s3 = s1;
    assert(strcmp(s3.c_str(), "hello") == 0);
    assert(s1.c_str() != s3.c_str());  // 深拷贝检查
}

// 测试移动操作
void test_move_operations() {
    // 移动构造
    string s1("hello");
    const char* original_data = s1.c_str();
    string s2(std::move(s1));
    
    assert(s2.c_str() == original_data);  // 数据被移动
    assert(s1.empty());                   // s1 被清空
    assert(s1.c_str() == nullptr);       // s1 的指针被置空
    
    // 移动赋值
    string s3;
    s3 = std::move(s2);
    assert(s3.c_str() == original_data);  // 数据被移动
    assert(s2.empty());                   // s2 被清空
    assert(s2.c_str() == nullptr);       // s2 的指针被置空
}

// 测试容量管理
void test_capacity_management() {
    string s;
    assert(s.capacity() == 15);  // 初始容量
    
    s.reserve(20);
    assert(s.capacity() >= 20);
    
    s.append("hello");
    size_t cap = s.capacity();
    s.shrink_to_fit();
    assert(s.capacity() == 15);  // 回到最小容量
}

// 测试 append 操作
void test_append_operations() {
    string s;
    
    // 普通append
    s.append("hello");
    assert(strcmp(s.c_str(), "hello") == 0);
    
    // 触发扩容的append
    s.append(" world");
    assert(strcmp(s.c_str(), "hello world") == 0);
    
    // 二进制数据append
    char binary[] = {'!', '\0', '!'};
    s.append(binary, 3);
    assert(s.size() == 14);
    assert(memcmp(s.data() + 11, binary, 3) == 0);
}

// 测试边界条件
void test_edge_cases() {
    // 空字符串
    string s1("");
    assert(s1.size() == 0);
    assert(s1.c_str()[0] == '\0');
    
    // 大量数据
    std::string long_str(1000, 'x');
    string s2(long_str.c_str());
    assert(s2.size() == 1000);
    assert(memcmp(s2.data(), long_str.c_str(), 1000) == 0);
}

// 测试异常安全性
void test_exception_safety() {
    // 测试空指针
    try {
        string s1(nullptr);
        assert(false);
    } catch (const std::invalid_argument&) {}
    
    try {
        string s2;
        s2.append(nullptr);
        assert(false);
    } catch (const std::invalid_argument&) {}
}

int main() {
    TEST_CASE(constructors);
    TEST_CASE(copy_operations);
    TEST_CASE(move_operations);
    TEST_CASE(capacity_management);
    TEST_CASE(append_operations);
    TEST_CASE(edge_cases);
    TEST_CASE(exception_safety);
    
    std::cout << "\nAll tests passed!" << std::endl;
    return 0;
}
View Code

 

posted @ 2025-11-16 14:05  墨尔基阿德斯  阅读(3)  评论(0)    收藏  举报