在我的程序中,我试图取消引用指向结构项目的指针,以获取其id,但我得到了"读取位置0xCCCCCCCC的访问冲突"。我尝试过很多不同的东西,局部变量,将指针回溯到代码中,不同的括号。。。不过什么都没有。我没有选择,无论我怎么努力,我都看不出问题。
这个问题可能有答案,但访问违规对我来说太普遍了,无法找到我想要的答案(而且大多数问题都是围绕数组的,这不是我的情况(。
在这里,我定义了一个简单的结构来保存我的数据。
struct Article {
public:
std::string id;
std::string title;
std::string text;
Article(std::string article_id, std::string article_title, std::string article_text) : id(article_id), title(article_title), text(article_text) {};
void toString();
};
接下来,我使用一本字典,将所有单词映射到它们出现的文章中。代码本身并没有完成,但单词映射应该包括所有必要的指针。
std::map<std::string, std::map<Article*, unsigned>> word_dict_;
我还保留了另一个vector<Article> articles_
,因为我保留了它们,所以在word_dict_中不应该出现空指针;
在这里生成字典。
void fulltext::generateDict() {
for (Article ar : articles_) {
unsigned wordStart;
bool isBuilding = false;
string buffer = "";
for (unsigned int it = 0; it <= ar.text.size(); ++it) {
char c;
if (it < ar.text.size())
c = ar.text.at(it);
else
c = ' ';
if (isalpha(c)) {
// start or middle of word
if (!isBuilding) {
isBuilding = true;
wordStart = it;
}
buffer += c;
}
else {
isBuilding = false;
if (buffer != "") {
stringToLower(buffer); // rewrites buffer to low case
// Here I tried creating &ar just for the laughs and it works just fine.
word_dict_[buffer][&ar] = wordStart;
buffer = "";
}
}
}
}
}
最后但同样重要的是,我想把它打印出来,真正的乐趣就从这里开始了。
void fulltext::printWordDict() {
cout << "Printing generated word dictionary: " << endl;
for (auto wordPair : word_dict_) {
cout << " " " << wordPair.first << " " " << endl;
cout << "There are " << wordPair.second.size() << " inputs." << endl;
for (pair<Article*, unsigned int> articlePair : wordPair.second) {
cout << (articlePair.first)->id << endl; // Here the access violation occurs
// Nothing seemingly works
// cout << articlePair.first->id; ... Access violation
// cout << (*articlePair.first).id; ... Access violation
// auto ar = articlePair.first; cout << ar->id; ... access violation
// auto ar = articlePair.first; cout << (*ar).id; ... access again
}
cout << endl;
}
cout << "Done." << endl;
}
这些函数是从主函数CCD_ 3中立即调用的。word_dict_是类私有变量。
如果需要代码的任何其他部分,请告诉我,尽管在这种情况下,其他部分都不应该出现任何问题。
for (Article ar : articles_) {
...
word_dict_[buffer][&ar] = wordStart;
...
}
在这里,您在字典中存储了一个指向ar
的指针,但是ar
在其作用域的末尾被销毁——当for循环结束时。因此,现在您在地图中存储了一个悬空指针,无法取消引用。
在地图中存储Article
对象而不是Article*
,或者确保Article
对象位于某个位置,只要地图中有指向它的指针即可。
如果对象位于articles_
容器中,则可能不需要将其复制到for循环中,而是执行以下操作:
for (Article& ar : articles_) {
..
word_dict_[buffer][&ar] = wordStart;
现在,您将获得一个指向位于article_
中的Article
对象的指针。
尽管稍后要注意如何处理article_
——如果对其执行移动对象的操作(根据容器类型的不同,可能会由于多种原因发生这种情况(,那么word_dict_
中的指针将无效。
for (Article ar : articles_)
这将执行文章的副本,作为局部变量。循环的下一次迭代一开始,这个局部变量就超出了作用域。
word_dict_[buffer][&ar] = wordStart;
在这里存储一个指向局部变量的指针,该指针仅在循环中有效。
如果您可以确保您的文章比您的地图更长寿,则可以存储指向存储在articles_
中的文章的指针。请注意,如果articles_
是std::vector
,当您向其中插入新文章时,它可能会被重新分配,因此必须小心地存储指向其中对象的指针,确保在std::vector
更改时使其无效。
如果以上所有内容听起来都像你的一杯茶,你很可能想创建一个引用到这篇文章,就像一样
for (Article& ar : articles_)
如果以上听起来有点过于复杂,你有两种可能的方法
使
word_dict_
映射按Value而不是指针存储Article
对象。这种方法的缺点是,您将文章存储两次,这具有逻辑含义(对地图中文章的更改不会反映在articles_
向量中,反之亦然(以及内存含义(您使用双倍的内存(使您的
articles_
矢量存储std::unique_ptr<Article>
。这样,您就不需要手动管理向量内部的重新定位。您仍然需要管理文章从articles_
向量中被删除的情况,并确保将其从word_dict_
映射中删除。这种方法的缺点是,它使您的类在默认情况下不可移植(std::unique_ptr
有一个已删除的复制构造函数(,这对您来说可能是个问题,也可能不是个问题。如果你需要复制它们,你需要手动提供一个复制ctor和复制分配操作符,以及手动实现或= default
其他3个特殊成员功能(见规则5(