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 上的析构函数并释放项目。

我做错了什么?

编辑:添加了 DictionaryMyString 类:


#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 被销毁时所有其他指针都被泄漏。