You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

C++ STL替代方案技术咨询:无STL实现核心功能的方案问询

C++ STL替代方案技术咨询:无STL实现核心功能的方案问询

完全懂你这种纠结——C++的底层控制感和语法灵活性确实香,但STL的复杂度(尤其是某些容器的黑箱行为、模板膨胀带来的二进制体积问题)真的容易让人头大。我自己在做轻量级嵌入式项目、追求极致性能的服务器程序时,也会刻意避开STL,下面就把我常用的替代方案给你掰扯清楚,全是实战里验证过的:

动态字符串

完全可以自己封装一个极简版本,核心就是管理char*的内存、长度和容量,逻辑比STL的std::string透明太多:

struct DynString {
    char* data;
    size_t len;
    size_t cap;

    DynString() : data(nullptr), len(0), cap(0) {}
    ~DynString() { free(data); }

    // 追加字符串的核心逻辑
    void append(const char* s) {
        size_t s_len = strlen(s);
        if (len + s_len >= cap) {
            // 扩容策略自定义,我一般用2倍扩容(也可以按固定步长,比如每次加1024字节)
            cap = (len + s_len + 1) * 2;
            data = (char*)realloc(data, cap);
            // 注意:realloc失败会返回nullptr,生产环境要加判断
        }
        memcpy(data + len, s, s_len);
        len += s_len;
        data[len] = '\0'; // 手动补结束符
    }

    // 也可以加个c_str()方法直接返回原生指针
    const char* c_str() const { return data ? data : ""; }
};

实用提示:如果是嵌入式场景,把realloc换成平台提供的内存分配接口(比如单片机里的heap_caps_malloc)就行,适配性拉满。

动态数组

和动态字符串思路一致,用模板做泛型支持(不用STL的模板特性,自己写极简模板就行):

template<typename T>
struct DynArray {
    T* data;
    size_t count;
    size_t capacity;

    DynArray() : data(nullptr), count(0), capacity(0) {}
    ~DynArray() { delete[] data; }

    void push_back(const T& val) {
        if (count >= capacity) {
            // 初始容量设4,之后2倍扩容
            capacity = capacity == 0 ? 4 : capacity * 2;
            T* new_data = new T[capacity];
            // 手动拷贝元素:POD类型用memcpy更高效,非POD类型调用拷贝构造
            if (std::is_trivially_copyable_v<T>) {
                memcpy(new_data, data, count * sizeof(T));
            } else {
                for (size_t i = 0; i < count; ++i) {
                    new_data[i] = data[i];
                }
            }
            delete[] data;
            data = new_data;
        }
        data[count++] = val;
    }

    T& operator[](size_t idx) { return data[idx]; }
    const T& operator[](size_t idx) const { return data[idx]; }
};

实用提示:如果是纯C风格的项目,把模板换成void*,再额外传元素大小,用memcpy做拷贝,兼容性更强。

计时

直接用平台原生API,比STL的std::chrono更直接,没有模板层的开销:

Windows 平台

#include <windows.h>
// 返回微秒级时间戳
long long get_timestamp() {
    LARGE_INTEGER freq, counter;
    QueryPerformanceFrequency(&freq);
    QueryPerformanceCounter(&counter);
    return (counter.QuadPart * 1000000) / freq.QuadPart;
}

Linux 平台

#include <time.h>
// 返回微秒级时间戳(用CLOCK_MONOTONIC避免系统时间被修改影响计时)
long long get_timestamp() {
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
}

线程与同步

同样用平台原生接口,比STL的std::threadstd::mutex更可控:

Windows 平台

#include <windows.h>
// 线程函数
DWORD WINAPI worker_thread(LPVOID param) {
    int* task_data = (int*)param;
    // 这里写线程逻辑,比如处理任务数据
    *task_data += 10;
    return 0;
}

// 使用示例
int main() {
    int data = 5;
    HANDLE thread = CreateThread(nullptr, 0, worker_thread, &data, 0, nullptr);
    WaitForSingleObject(thread, INFINITE); // 等待线程结束
    CloseHandle(thread);
    return 0;
}
// 同步用CriticalSection(轻量级)或Event(异步通知)
CRITICAL_SECTION cs;
InitializeCriticalSection(&cs);
EnterCriticalSection(&cs);
// 临界区代码
LeaveCriticalSection(&cs);
DeleteCriticalSection(&cs);

Linux 平台

#include <pthread.h>
// 线程函数
void* worker_thread(void* param) {
    int* task_data = (int*)param;
    *task_data += 10;
    return nullptr;
}

// 使用示例
int main() {
    int data = 5;
    pthread_t tid;
    pthread_create(&tid, nullptr, worker_thread, &data);
    pthread_join(tid, nullptr); // 等待线程结束
    return 0;
}
// 同步用pthread_mutex_t
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&mutex);
// 临界区代码
pthread_mutex_unlock(&mutex);
pthread_mutex_destroy(&mutex);

内存管理

除了直接用malloc/freenew/delete,高频场景下我会自己写极简内存池,减少碎片和分配开销:

// 针对固定大小对象的内存池(适合频繁创建销毁同类型小对象)
struct FixedMemPool {
    void* free_list;
    size_t obj_size;

    FixedMemPool(size_t obj_sz) : free_list(nullptr), obj_size(obj_sz) {}

    void* allocate() {
        // 优先从空闲链表取
        if (free_list) {
            void* ptr = free_list;
            free_list = *(void**)ptr; // 链表头后移
            return ptr;
        }
        // 没有空闲块就从堆上分配
        return malloc(obj_size);
    }

    void deallocate(void* ptr) {
        if (!ptr) return;
        // 把释放的块挂到空闲链表头部
        *(void**)ptr = free_list;
        free_list = ptr;
    }
};

其他常用功能(比如字符串格式化)

不用STL的stringstream,直接用C标准库的vsnprintf封装:

#include <stdarg.h>
// 简单的字符串格式化函数
int str_format(char* buf, size_t buf_size, const char* fmt, ...) {
    va_list args;
    va_start(args, fmt);
    int ret = vsnprintf(buf, buf_size, fmt, args);
    va_end(args);
    return ret; // 返回写入的字符数(不含结束符)
}

其实核心思路就是用平台原生API+极简封装,完全避开STL的复杂度,同时保留C++的底层控制感。如果是特定场景(比如嵌入式),还可以把内存分配换成平台提供的内存池(比如RTOS的动态内存接口),适配性拉满。有具体场景的话,还能再细化优化细节~

火山引擎 最新活动