C++:custrom字符串类中的sigtrap错误
在过去的两天中,我一直在搜寻互联网,但找不到发生这种情况的理由。
我的字符串类以人们期望的方式工作:它从堆上的连续内存的初始块开始(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 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
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 usememset()
to set the values ofsize
characters (which can be larger than 128) in mydata
pointer, which only has 128 bytes allocated to it (initially).By changing
size
toMIN_SIZE
as thememset()
argument, everything has been resolved.Many thanks to user4581301.
I will be accepting this answer as soon as I can to close the question.