繁体   English   中英

C++:cusstrom String 类中的 SIGTRAP 错误

[英]C++: SIGTRAP error in custrom String class

在过去的两天里,我在互联网上搜索,找不到发生这种情况的原因。

我的字符串类以人们期望的方式工作:它从堆上的一个初始连续内存块(128 字节)开始,然后根据需要调整大小。

我对new的所有调用都与在相应指针上对delete[]单个调用相匹配。

SIGTRAP 错误仅在调用析构函数时发生(最后一次使用delete[] )。

为了产生一个最小的可重现示例,我将代码(大约 1400 行)减少到如下所示(以及似乎导致错误的原因)。

#include <string>
#include <iostream>
#include <cstring>

static int MIN_SIZE = 128;

    char *setchr_c(char *str, const char ch, size_t pos) {
        if (str == nullptr) {
            return nullptr;
        }
        *(str + pos) = ch;
        return str;
    }

    class String {
    private:
        char *data = nullptr;
        char *string = nullptr;
        size_t length_w_null = 0;
        size_t size = 0;
        size_t space_front = 0;
        size_t space_back = 0;
        bool is_empty = true;

        void set_size(bool def_do = true) {
            if (def_do) {
                do {
                    size *= 2;
                } while (size < length_w_null);
                return;
            }
            while (size < length_w_null) {
                size *= 2;
            }
        }

        void constructor(const char *str, bool after_empty = false) {
            size = MIN_SIZE;
            length_w_null = strlen(str) + 1;
            set_size(false);
            if (after_empty) { // this is to avoid re-assigning the memory if not necessary
                if (size != MIN_SIZE) {
                    // free(data);
                    printf("CTOR AFTER EMPTY DELETE, DELETING: %x\n", data);
                    delete[] data;
                    // data = (char *) malloc(size);
                    printf("CTOR AFTER EMPTY NEW, SIZE: %llu, ", size);
                    data = new char[size];
                    printf("ADDRESS: %x\n", data);
                }
            } else {
                // data = (char *) malloc(size);
                printf("CTOR ELSE NEW, SIZE: %llu, ", size);
                data = new char[size];
                printf("ADDRESS: %x\n", data);
            }
            memset(data, '\0', size);
            string = data + get_first_pos();
            setchr_c(string, '\0', length_w_null - 1);
            strcpy(string, str);
            space_front = get_first_pos();
            space_back = is_even(length_w_null) ? space_front : space_front + 1;
            is_empty = false;
        }

        void empty_constructor() {
            // data = (char *) malloc(MIN_SIZE);
            printf("EMPTY CTOR NEW, MINSIZE: %llu, ", MIN_SIZE);
            data = new char[MIN_SIZE];
            printf("ADDRESS: %x\n", data);
            memset(data, '\0', size);
            string = nullptr;
            length_w_null = 0;
            size = MIN_SIZE;
            space_front = MIN_SIZE / 2;
            space_back = MIN_SIZE / 2;
            is_empty = true;
        }

        static bool is_even(size_t num) {
            return num % 2 == 0;
        }

        [[nodiscard]] unsigned long get_first_pos() const {
            size_t new_len = length_w_null;
            if (!is_even(new_len)) {
                new_len++;
            }
            unsigned long pos = size / 2 - (new_len) / 2;
            return pos;
        }

    public:
        static const size_t nopos = -1;
        String() {
            empty_constructor();
        }

        String(char ch) {
            if (ch == '\0') {
                empty_constructor();
            } else {
                const char str[2]{ch, '\0'};
                constructor(str);
            }
        }

        String(const char *str) {
            if (str == nullptr) {
                return;
            }
            if (strlen(str) == 0) {
                empty_constructor();
            } else {
                constructor(str);
            }
        }

        void append_back(const char *str) {
            if (str == nullptr) {
                return;
            }
            if (is_empty) {
                constructor(str, true);
                return;
            }
            size_t l = strlen(str);
            size_t old_l = length_w_null - 1;
            length_w_null += l;
            if (l + 1 > space_back) {
                set_size();
                char *old_data = data;
                char *old_str = string;
                // data = (char *) malloc(size);
                printf("APPEND BACK NEW, SIZE: %llu, ", size);
                data = new char[size];
                printf("ADDRESS: %x\n", data);
                memset(data, '\0', size);
                string = data + get_first_pos();
                strcpy(string, old_str);
                // free(old_data);
                printf("APPEND BACK DELETE OLD_DATA, DELETING: %x\n", old_data);
                delete[] old_data;
                space_front = get_first_pos();
                space_back = is_even(length_w_null) ? space_front : space_front + 1;
            }
            strcpy(string + old_l, str);
            space_back -= l;
        }

        void append_front(const char *str) {
            if (str == nullptr) {
                return;
            }
            if (is_empty) {
                constructor(str, true);
                return;
            }
            size_t l = strlen(str);
            length_w_null += l;
            char gone = *string;
            if (l > space_front) {
                set_size();
                char *old_data = data;
                char *old_str = string;
                // data = (char *) malloc(size);
                printf("APPEND FRONT NEW, SIZE: %llu, ", size);
                data = new char[size];
                printf("ADDRESS: %x\n", data);
                memset(data, '\0', size);
                string = data + get_first_pos();
                strcpy(string + l, old_str);
                // free(old_data);
                printf("APPEND FRONT DELETE OLD_DATA, DELETING: %x\n", old_data);
                delete[] old_data;
                strcpy(string, str);
                space_front = get_first_pos();
                space_back = is_even(length_w_null) ? space_front : space_front + 1;
            } else {
                strcpy(string - l, str);
                string -= l;
                space_front -= l;
            }
            setchr_c(string, gone, l);
        }

        void push_back(char ch) {
            if (ch == 0) {
                return;
            }
            const char str[2] = {ch, '\0'};
            append_back(str);
        }

        void push_front(char ch) {
            if (ch == 0) {
                return;
            }
            const char str[2] = {ch, '\0'};
            append_front(str);
        }

        void clear() noexcept {
            // free(data);
            printf("CLEAR DELETE, DELETING: %x\n", data);
            delete[] data;
            empty_constructor();
        }

        size_t get_size() const {
            return size;
        }

        size_t get_length() const {
            return length_w_null == 0 ? 0 : length_w_null - 1;
        }

        const char *c_str() const noexcept {
            return string;
        }

        ~String() {
            // free(data);
            printf("DTOR DELETE, DELETING: %x\n", data);
            delete[] data;
        }

        friend std::ostream& operator<<(std::ostream& os, const String& str);
    };
    std::ostream& operator<<(std::ostream& os, const String& str) {
        os << str.string;
        return os;
    }
using namespace std;
int main() {
    String bro;
    char array[] = "eeee;;dlfkjas;j;a;lAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsdjfk";
    bro.clear();
    for (const char &ch : array) {bro.push_front(ch);}
    bro.clear();
    bro.append_back("Let us see!");
    cout << bro << endl;
    return 0;
}

我添加了一些 printf() 语句来检查地址,没有明显错误。

我得到的示例输出是:

EMPTY CTOR NEW, MINSIZE: 128, ADDRESS: 9b651920
CLEAR DELETE, DELETING: 9b651920
EMPTY CTOR NEW, MINSIZE: 128, ADDRESS: 9b651920
APPEND FRONT NEW, SIZE: 256, ADDRESS: 9b6519b0
APPEND FRONT DELETE OLD_DATA, DELETING: 9b651920
CLEAR DELETE, DELETING: 9b6519b0
EMPTY CTOR NEW, MINSIZE: 128, ADDRESS: 9b651920
Let us see!
DTOR DELETE, DELETING: 9b651920

...在程序崩溃之前。

编译器:Windows 上的 MinGW。

user4581301 非常友好地检查了我的代码,并指出了我的empty_constructor()成员函数中的明显错误:我使用memset() ) 在我的data指针中设置size个字符(可以大于 128)的值,它(最初)只分配了 128 个字节。

通过将size更改为MIN_SIZE作为memset()参数,一切都已解决。

非常感谢 user4581301。

我会尽快接受这个答案来结束这个问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM