C++:custrom字符串类中的sigtrap错误

发布于 2025-02-04 06:16:42 字数 8464 浏览 5 评论 0原文

在过去的两天中,我一直在搜寻互联网,但找不到发生这种情况的理由。

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

我对new的所有调用都与相应指针上的A single 调用到delete []

Sigtrap错误仅在调用destructor时发生(使用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。

I have scoured the internet for the past two days and can find no reason for this to be occurring.

My string class works in the way one would expect: it starts with an initial block of contiguous memory on the heap (128 bytes), and then resizes if need be.

All of my calls to new are matched with a single call to delete[] on the corresponding pointer.

The SIGTRAP error only occurs as the destructor is being called (which uses delete[] a final time).

In order to produce a minimal reproducible example, I have reduced the code (about 1400 lines) to what is seen below (and what seems to be causing the error).

#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;
}

I added in a few printf() statements to check the addresses, and there is nothing obviously wrong.

A sample output I get is:

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

... before the program crashes.

Compiler: MinGW on Windows.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

狼亦尘 2025-02-11 06:16:42

user4581301非常友好,可以检查我的代码,并指出了我的empty_constructor()成员函数中的公然故障:我使用memset()设置size 字符(可以大于128)在我的数据指针中,该指针仅分配了128个字节(最初)。

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

非常感谢User4581301。

我将尽快接受这个答案来解决这个问题。

user4581301 has been kind enough to check my code and has pointed out the blatant fault in my empty_constructor() member function: I use memset() to set the values of size characters (which can be larger than 128) in my data pointer, which only has 128 bytes allocated to it (initially).

By changing size to MIN_SIZE as the memset() argument, everything has been resolved.

Many thanks to user4581301.

I will be accepting this answer as soon as I can to close the question.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文