Quite a weird clang question

I've tried several google searches before making this post, but honestly, I don't know what to look for. I have a C ++ project and we are happy to use GNU compilers (g ++). Today I tried to compile with clang ++ and got a segfault.

Okay, okay, I can handle it. After examining my code and printing some things, I was able to fix this issue. However, the solution deeply complicates and confuses me.

Here's the situation: I am using a tree data structure that stores the Ligament class, but I store it in std :: vector. I do this by keeping a vector of "children", which are actually integer offsets between parent and child in the vector. This way I can access the children using this pointer i.e.

child = this[offset];

      

However, none of this matters. Here's the problem: I have a function Ligament :: addChild (int) that takes an integer and pushes it back into a vector that is a member of the bundle:

void Ligament::addChild(uint32_t offset){
   children.push_back(offset);
}

      

Very simple stuff. In general, I am passing addChild an argument that is returned from a recursive function called fill:

//starting at root
uint32_t fill(vector<Ligament>& lVec, TiXmlElement * el){
    //store current size here, as size changes during recursion
   uint32_t curIdx = lVec.size();
   lVec.push_back(createLigament());

   //Add all of this Ligament children
   TiXmlElement * i = el->FirstChildElement("drawable");
   for (; i; i=i->NextSiblingElement("drawable")){
      uint32_t tmp = fill(lVec, i) - curIdx;
      lVec[curIdx].addChild(tmp);

      //Does not work in clang++, but does in g++
      //lVec[curIdx].addChild(fill(lVec,i)-curIdx);
   }

   //return the ligament index
   return curIdx;
}

      

The fill function is called on an XML element and traverses its children first.

Sorry if this is all unclear, but the crux of the problem seems to be that for a loop. For some reason, I have to store the return value of the variable fill call before sending it to the addChild function.

If I don't store it in a temporary variable, the addChild function doesn't seem to resize the children, but I can't imagine why.

To test all this, I printed out the size of the child vector before and after these calls, and it never went above 1. Only when I called addChild with a value that wasn't directly returning from the function, it seemed to work.

I also printed out the offset values โ€‹โ€‹inside the addChild function as well as inside the for loop before calling it. In all cases, the values โ€‹โ€‹were the same in both clang ++ and g ++.

Since the issue is resolved I was able to move forward, but this is what I expect to work out. Is there something I am doing wrong?

Feel free to yell at me if I can do more to make this matter clearer.

ALSO: Now I understand that passing lVec by reference through these recursions can be bad as calling push_back can cause the address to change. Is this a legitimate issue?

EDIT:

As people pointed out, my last issue ended up being related to this question. The fill fill can resize the vector, while the lVec [curIdx] = modifier will change the element in the vector. The order in which these things happen can have serious consequences.

Is a valid tmp variable used as a continuation? There's still a reallocation problem going on ... I think I'll use the SHR sentence of the map and then convert it to a vector when all is said and done.

+3


source to share


2 answers


I think this behavior is undefined.

you insert a vector and modify it in the same command.



one compiler may execute first fill

and another may receive first lVec[curIdx]

.

if so, it will work for both compilers when you use map<uint32_t,uint32_t>

instead vector

. since the card does not require the memory to be sequential.

+2


source


// Does not work in clang++, but does in g++:
lVec[curIdx].addChild(fill(lVec,i)-curIdx);

      



The error you are seeing is related to the evaluation order dependency. Since it fill(lVec, i)

can lead to a reallocation of elements lVec

, the program will have undefined behavior if lVec[curIdx]

evaluated before fill(lVec,i)

. The order in which the function arguments are evaluated - and the postfix expression specifying which function to call - is not specified.

+5


source







All Articles