我正在尝试为我所在的类构建关系数据库。
正在发生的事情是,当我处理“事实”和“查询”输入时,我创建了一个新的关系对象。然后我打印出来。如果我一次运行一个它们处理得很好,但如果我背靠背运行它们,第二个修改另一个关系对象中的标记向量的内容。
class Database
{
private:
datalogProgram program;
Relation theSchemes;
Relation theFacts;
std::vector<Token> FactsOrder;
public:
Database(datalogProgram input);
Database();
~Database();
Relation processSchemes(datalogProgram processme);
Relation processFacts(datalogProgram processme);
};
我为所有的cout道歉,我一直试图调试这些东西几个小时!
#include "Database.h"
#include <sstream>
Database :: Database(datalogProgram input)
{
// So first I will make a map with relations representing the Schemes Facts and Queries
// Thus I will have a database of schemes facts and queries, rules excluded and ignored for now.
program = input;
theSchemes = processSchemes(program);
theFacts = processFacts(program);
// just checking on progress.
std::cout << "SCHEMES" << std::endl;
theSchemes.printRelation();
std::cout << "FACTS" << std::endl;
theFacts.printRelation();
}
Database :: Database() {}
Database :: ~Database() {}
Relation Database :: processSchemes(datalogProgram input)
{
Relation temp;
// LETS START WITH SCHEMES
std::cout << "processing schemes" << std::endl;
std::vector<Scheme>* schemes = input.returnSchemeList();
// Process First Scheme
// Populate this first vector with ID's from schemes.
// std::vector<Token*> firstTuple;
std::vector<Token*> firstTuple;
std::vector<Token> idListONE;
firstTuple.push_back(input.returnFirstScheme()->returnFirstID());
// std::vector<Token> idListONE;
idListONE = input.returnFirstScheme()->returnCLEANidLIST();
for(int i = 0; i < input.returnFirstScheme()->returnCLEANidLIST().size(); i++)
firstTuple.push_back(&idListONE[i]);
temp = *new Relation(input.returnFirstScheme()->returnName(), firstTuple);
// NOW I NEED TO PROCESS THE REST OF THE SCHEMES
//Take a scheme off of the list, and work on it just like I did above.
for(int j = 0; j < schemes->size(); j++) {
// Populate this first vector with ID's from schemes.
std::vector<Token*> first;
first.clear();
first.push_back(schemes->at(j).returnFirstID());
std::vector<Token> idLista;
idLista.clear();
idLista = schemes->at(j).returnCLEANidLIST();
for(int i = 0; i < schemes->at(j).returnCLEANidLIST().size(); i++)
first.push_back(&idLista[i]);
temp.relationInsert(schemes->at(j).returnName(), first);
}
return temp;
//
// At this point I shoudl have a map with "Schemes" pointing to Relation Objects.
// I want to verify that this is working, so print out all data collected so far.
}
Relation Database :: processFacts(datalogProgram input)
{
Relation temporary;
// NOW WE PROCESS FACTS
// Order does matter, so I will create a vector to use as a key.
std::cout << "procesing facts" << std::endl;
std::vector<Fact>* facts = input.returnFactList();
std::string OUT2;
std::ostringstream convert2;
convert2 << facts->size();
OUT2 = convert2.str();
std::cout << "THE NUMBER OF FACTS IS " << OUT2 << std::endl;
// NOW I NEED TO PROCESS THE REST OF THE
//Take a scheme off of the list, and work on it just like I did above.
std::vector<Token*> firstTuple;
std::vector<Token> idListONE;
for(int j = 0; j < facts->size(); j++) {
std::cout << "NEW ITERATION:" << std::endl;
if(j==0) {
std::cout << "processing first fact" << std::endl;
// is the first Fact!
firstTuple.clear();
std::cout << "processing first fact --> tuple" << std::endl;
firstTuple.push_back(facts->at(j).returnFirstString());
idListONE.clear();
std::cout << "FIRST STRINGLIST" << std::endl;
idListONE = *facts->at(j).returnCleanStringList();
for(int i = 0; i < idListONE.size(); i++) {
std::cout << "FIRST STRING ITER" << std::endl;
firstTuple.push_back(&idListONE[i]);
}
FactsOrder.push_back(*facts->at(j).returnName());
std::cout << "creating first fact" << std::endl;
temporary = Relation(facts->at(j).returnName(), firstTuple);
} else {
std::cout << "processing A fact (ITER)" << std::endl;
// Populate this first vector with ID's from schemes.
std::vector<Token*> first;
first.clear();
std::cout << "processing fact, firststring (ITER)" << facts->at(j).returnFirstString()->getTokensValue() << std::endl;
first.push_back(facts->at(j).returnFirstString());
std::vector<Token> idLista;
idLista.clear();
std::cout << "getting stringlist (ITER)" << std::endl;
idLista = *facts->at(j).returnCleanStringList();
for(int i = 0; i < idLista.size(); i++) {
std::cout << "processing stringlist (ITER) ITER" << std::endl;
first.push_back(&idLista[i]);
}
FactsOrder.push_back(*facts->at(j).returnName());
std::cout << "adding fact" << std::endl;
temporary.relationInsert(facts->at(j).returnName(), first);
}
}
return temporary;
}
就这样你可以看到它
Relation :: Relation(Token* key,std::vector<Token*> tuple)
{
std::pair<Token*,std::vector<Token*> > mypair (key,tuple);
contents.insert(mypair);
}
Relation :: Relation() {}
Relation :: ~Relation() {}
void Relation :: relationInsert(Token* key,std::vector<Token*> tuple)
{
std::pair<Token*,std::vector<Token*> > mypair (key,tuple);
contents.insert(mypair);
}
void Relation :: printRelation()
{
std::cout << "PRINT RELATION CALLED" << std::endl;
std::multimap<Token*,std::vector<Token*> >::iterator mapIT;
for(mapIT = contents.begin() ; mapIT != contents.end() ; mapIT ++) {
std::cout << "Key: " << mapIT->first->getTokensValue() "\nValues:" << std::endl;
for(int x = 0; x< mapIT->second.size() ; x++)
std::cout << " " << mapIT->second.at(x)->getTokensValue() << std::endl;
}
}
答案 0 :(得分:1)
要解决您的问题,您必须在代码中找出对象/指针的所有权。 Relation
包含指向Token的指针和指向Tokens的其他指针列表之间的关系。可以保留Token*
而不是令牌副本。 (特别是如果令牌可能是大字,则您不想复制)。但谁“拥有”并管理令牌?
让我们看一个例子
std::vector<Token*> firstTuple;
std::vector<Token> idListONE;
你按照以下方式进入它:
firstTuple.push_back(&idListONE[i]);
因此,firstTuple标记是指向idListONE内部标记的指针。 可能有效但您必须记住,只要idListONE被释放或其内存被更改(例如其大小增加),firstTuple就会变为无效,因为它现在将指向已释放的内存并使用它可能有不确定的结果,可能会导致程序崩溃。
实际上几行后你就犯了这个错误:
temporary = Relation(facts->at(j).returnName(), firstTuple);
temporary是一个包含令牌指针列表的Relation。它复制列表,这意味着它复制了令牌指针。然而,一旦退出函数idListONE
,它复制的指针就会复制到属于idListONE
的标记,并且关系中的指针不再有效,并且使用它们可能是问题的一个来源你看到了。 代码中可能还有其他问题
一般来说,使用指针和使用对象时似乎存在很多混淆。
请看以下声明:
temp = *new Relation(input.returnFirstScheme()->returnName(), firstTuple);
new Relation(...)
将在堆上分配内存并初始化一个Relation。
temp = *<ptr>
将使用operator =将右侧的内容复制到temp
。堆上的关系被遗忘,其内存泄露。
另一个例子:
idListONE.clear();
std::cout << "FIRST STRINGLIST" << std::endl;
idListONE = *facts->at(j).returnCleanStringList();
首先清除idListONE,然后使用operator =用新列表覆盖它。
最后你真的应该选择一种风格并遵守它。从长远来看,它使代码更清晰。
如果您使用Camelize变量名称,则始终执行:idListONE - &gt; idListOne
还要避免像'idListONE'这样的成员,你真的需要为第一个索引使用不同的变量吗?