指针的神秘行为。 (对象的内部元素发生了变化)

时间:2014-04-14 04:21:32

标签: c++ pointers

我正在尝试为我所在的类构建关系数据库。

正在发生的事情是,当我处理“事实”和“查询”输入时,我创建了一个新的关系对象。然后我打印出来。如果我一次运行一个它们处理得很好,但如果我背靠背运行它们,第二个修改另一个关系对象中的标记向量的内容。

Database.h

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);
};

Database.cpp

我为所有的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.cpp

就这样你可以看到它

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;
    }
}

1 个答案:

答案 0 :(得分:1)

要解决您的问题,您必须在代码中找出对象/指针的所有权。 Relation包含指向Token的指针和指向Tokens的其他指针列表之间的关系。可以保留Token*而不是令牌副本。 (特别是如果令牌可能是大字,则您不想复制)。但谁“拥有”并管理令牌?

让我们看一个例子

std::vector<Token*> firstTuple;
std::vector<Token> idListONE;
  • idListONE是实际令牌的向量。它是一个函数局部变量,因此当我们退出函数时它将被丢弃。
  • firstTuple是令牌指针的向量。

你按照以下方式进入它:

      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 =用新列表覆盖它。

  • 你为什么要清楚你正在写的清单?
  • 为什么从returnCleanStringList()返回指向列表的指针?而不是复制列表或const ref到内部列表?
  • 如果你决定returnCleanStringList()应该通过指针返回一个列表而不是值,那么为什么你要做的第一件事就是复制它? / LI>

最后你真的应该选择一种风格并遵守它。从长远来看,它使代码更清晰。

如果您使用Camelize变量名称,则始终执行:idListONE - &gt; idListOne

还要避免像'idListONE'这样的成员,你真的需要为第一个索引使用不同的变量吗?