C++:当临时 std::map 超出范围时,std::map 的项目被释放
C++: Items of std::map are deallocated when temporary std::map goes out of scope
我不是 C++ 用户,我只是为了好玩而尝试一些东西,但我被卡住了,我想,我做错了什么。
我有一个 std::map
自己的 类 (std::map<MyClass*, MyClass*>
),我正在尝试过滤掉一个子集,将其存储为临时(本地实例)std::map<MyClass*, MyClass*>
.问题是,当临时映射超出范围时,将调用 MyClass
上的析构函数并释放项目。
我做错了什么?
编辑:添加了 Dictionary
和 MyString
类:
#include <iostream>
#include "Dictionary.h"
Dictionary::Dictionary(const char *filename) {
entries = new std::map<MyString *, MyString *>();
load(filename);
}
void Dictionary::load(const char *filename) {
FILE *fh = fopen(filename, "r");
if (!fh) {
printf("Unable to open file: %s\n", filename);
return;
}
size_t len;
while (!feof(fh)) {
char *line = fgetln(fh, &len);
if (len > 60) {
printf("Line too long, skipping.\n");
continue;
}
// find ";" character and change it to [=12=]
char *delimiter = strstr(line, ";");
if (delimiter == nullptr) {
printf("Line does not contain delimiter.\n");
continue;
}
// if last character in line is newline, subtract length
if (line[len - 1] == '\n') {
len--;
}
entries->insert(std::pair<MyString *, MyString *>(
new MyString(line, (size_t) (delimiter - line)),
new MyString(delimiter + 1, (size_t) (len - (delimiter - line + 1)))));
}
fclose(fh);
}
void Dictionary::list(ComparisonOperations op, MyString *sub) {
std::map<MyString *, MyString *> results;
for (auto &entry : *entries) {
switch (op) {
case StartingOp:
if (entry.first->beginsWith(*sub)) {
results.insert(entry);
}
break;
case ContainingOp:
if (entry.first->contains(*sub)) {
results.insert(entry);
}
break;
case EndingOp:
if (entry.first->endsWith(*sub)) {
results.insert(entry);
}
break;
}
}
// print results
Dictionary::print(std::cout, results);
}
void Dictionary::print(std::ostream &os, std::map<MyString *, MyString *> &results) {
if (results.empty()) {
os << "No match found." << std::endl;
} else if (results.size() == 1) {
auto result = results.begin();
os << (MyString) *(result->first)
<< " => " << (MyString) *(result->second) << std::endl;
} else {
for (auto &result : results) {
os << (MyString) *(result.first) << std::endl;
}
}
}
---
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include "MyString.h"
MyString::MyString() {
buffer = (char *) malloc(1);
memset(buffer, 0, 1);
}
MyString::MyString(const char *str) {
buffer = (char *) malloc(MAX_MY_STRING_LEN + 1);
memset(buffer, 0, MAX_MY_STRING_LEN + 1);
strncpy(buffer, str, MAX_MY_STRING_LEN);
}
MyString::MyString(const char *str, int len) {
buffer = (char *) malloc(len + 1);
memset(buffer, 0, len + 1);
strncpy(buffer, str, len);
}
MyString::~MyString() {
if (buffer != nullptr) {
printf("dealloc string %s!", buffer);
free(buffer);
}
buffer = nullptr;
}
bool MyString::operator==(const MyString &cmp) const {
return strcmp(buffer, cmp.buffer) == 0;
}
bool MyString::operator<(const MyString &cmp) const {
return strcmp(buffer, cmp.buffer) < 0;
}
bool MyString::beginsWith(const MyString &sub) const {
return strstr(buffer, sub.buffer) == buffer;
}
bool MyString::contains(const MyString &sub) const {
return strstr(buffer, sub.buffer) != nullptr;
}
bool MyString::endsWith(const MyString &sub) const {
char *pos = strstr(buffer, sub.buffer);
return (pos - buffer + strlen(sub.buffer)) == strlen(buffer);
}
void MyString::print() {
printf("%s\n", buffer);
}
std::ostream &operator<<(std::ostream &os, const MyString &str) {
return os << ((const char *) str.buffer);
}
PS:不,这不是我的学校作业,它实际上是一个朋友的学校作业,我只是为了好玩而尝试,因为正如你所看到的,我的 C++ 已经生锈了。
由于 MyString
没有复制构造函数,Dictionary::print
中的表达式 (MyString) *(result->first)
创建了一个临时对象,它借用了对底层数据的引用,然后将其从下面释放出来过早的原主人。
也就是说,通过 Dictionary
class 使用指针意味着当 Dictionary
被销毁时所有其他指针都被泄漏。
我不是 C++ 用户,我只是为了好玩而尝试一些东西,但我被卡住了,我想,我做错了什么。
我有一个 std::map
自己的 类 (std::map<MyClass*, MyClass*>
),我正在尝试过滤掉一个子集,将其存储为临时(本地实例)std::map<MyClass*, MyClass*>
.问题是,当临时映射超出范围时,将调用 MyClass
上的析构函数并释放项目。
我做错了什么?
编辑:添加了 Dictionary
和 MyString
类:
#include <iostream>
#include "Dictionary.h"
Dictionary::Dictionary(const char *filename) {
entries = new std::map<MyString *, MyString *>();
load(filename);
}
void Dictionary::load(const char *filename) {
FILE *fh = fopen(filename, "r");
if (!fh) {
printf("Unable to open file: %s\n", filename);
return;
}
size_t len;
while (!feof(fh)) {
char *line = fgetln(fh, &len);
if (len > 60) {
printf("Line too long, skipping.\n");
continue;
}
// find ";" character and change it to [=12=]
char *delimiter = strstr(line, ";");
if (delimiter == nullptr) {
printf("Line does not contain delimiter.\n");
continue;
}
// if last character in line is newline, subtract length
if (line[len - 1] == '\n') {
len--;
}
entries->insert(std::pair<MyString *, MyString *>(
new MyString(line, (size_t) (delimiter - line)),
new MyString(delimiter + 1, (size_t) (len - (delimiter - line + 1)))));
}
fclose(fh);
}
void Dictionary::list(ComparisonOperations op, MyString *sub) {
std::map<MyString *, MyString *> results;
for (auto &entry : *entries) {
switch (op) {
case StartingOp:
if (entry.first->beginsWith(*sub)) {
results.insert(entry);
}
break;
case ContainingOp:
if (entry.first->contains(*sub)) {
results.insert(entry);
}
break;
case EndingOp:
if (entry.first->endsWith(*sub)) {
results.insert(entry);
}
break;
}
}
// print results
Dictionary::print(std::cout, results);
}
void Dictionary::print(std::ostream &os, std::map<MyString *, MyString *> &results) {
if (results.empty()) {
os << "No match found." << std::endl;
} else if (results.size() == 1) {
auto result = results.begin();
os << (MyString) *(result->first)
<< " => " << (MyString) *(result->second) << std::endl;
} else {
for (auto &result : results) {
os << (MyString) *(result.first) << std::endl;
}
}
}
---
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include "MyString.h"
MyString::MyString() {
buffer = (char *) malloc(1);
memset(buffer, 0, 1);
}
MyString::MyString(const char *str) {
buffer = (char *) malloc(MAX_MY_STRING_LEN + 1);
memset(buffer, 0, MAX_MY_STRING_LEN + 1);
strncpy(buffer, str, MAX_MY_STRING_LEN);
}
MyString::MyString(const char *str, int len) {
buffer = (char *) malloc(len + 1);
memset(buffer, 0, len + 1);
strncpy(buffer, str, len);
}
MyString::~MyString() {
if (buffer != nullptr) {
printf("dealloc string %s!", buffer);
free(buffer);
}
buffer = nullptr;
}
bool MyString::operator==(const MyString &cmp) const {
return strcmp(buffer, cmp.buffer) == 0;
}
bool MyString::operator<(const MyString &cmp) const {
return strcmp(buffer, cmp.buffer) < 0;
}
bool MyString::beginsWith(const MyString &sub) const {
return strstr(buffer, sub.buffer) == buffer;
}
bool MyString::contains(const MyString &sub) const {
return strstr(buffer, sub.buffer) != nullptr;
}
bool MyString::endsWith(const MyString &sub) const {
char *pos = strstr(buffer, sub.buffer);
return (pos - buffer + strlen(sub.buffer)) == strlen(buffer);
}
void MyString::print() {
printf("%s\n", buffer);
}
std::ostream &operator<<(std::ostream &os, const MyString &str) {
return os << ((const char *) str.buffer);
}
PS:不,这不是我的学校作业,它实际上是一个朋友的学校作业,我只是为了好玩而尝试,因为正如你所看到的,我的 C++ 已经生锈了。
由于 MyString
没有复制构造函数,Dictionary::print
中的表达式 (MyString) *(result->first)
创建了一个临时对象,它借用了对底层数据的引用,然后将其从下面释放出来过早的原主人。
也就是说,通过 Dictionary
class 使用指针意味着当 Dictionary
被销毁时所有其他指针都被泄漏。