Search code examples
c++stringmemoryode-library

C++ string and memory management


I am now working on a rather complex project involving control of a simulated robotic arm. I finished a first version of the project and it is working fine. I just added some new code that collect some information about the system at each iteration, save it in some arrays, and at the end prints everything in a file for later analysis.

Now, something real strange is happening. If I define the file in which the data will be saved as follow:

const std::string SAVEFILE = "C:\\Users\\Vincent\\Desktop\\ta";

everything works fine, exactly the same as it did before I add the new code (plus saving the data).

But if I define it as follow:

const std::string SAVEFILE = "C:\\Users\\Vincent\\Desktop\\tacit.txt";

then the system behaves in another way. Does not crash, but the robotic arm moves differently.

I tried to comment all the code that was making use of SAVEFILE, and even any new code related to data saving, but the problem persists.

I know that with only this information, it is unlikely that anybody can tell me what is wrong, but would anybody have some advice what direction to look ? Would it make sense to think that a long string overwrite the value of some other variable ? How can it be possible ? Some guideline of clean C++ programming I might have broken ?

That some array is misbehaving sounds possible, and was the first thing I checked. I guess it should come from the arrays saving data, as they are the only new one. Thing is, even when I comment all the corresponding code, no change.

I try to give more information about my code. Here where I first use SAVEFILE (last argument of the runExperiment function)

int main(int argc, char *argv[])    {
  std::vector<Controller*> controllers;
  controllers.push_back(getConstrainedPDT(0,true));
  controllers.push_back(getConstrainedPDT(1,true));
  controllers.push_back(getConstrainedPDT(2,true));
  runExperiment(controllers,LENGTHS,WEIGHTS,RADIUS,ANGLEMIN,ANGLEMAX,MAXTORQUES,PUSHVECTOR,GRAVITY,RUNTIME,TIMESTEP,XTARGET,YTARGET,ITERATIONSAVEDATA,SAVEFILE);
  return 1;
}

and here the code of the function:

void runExperiment(std::vector<Controller*> controllers,const double * lengths, const double* weights, const double radius, const double* angleMin, const double* angleMax, const double* maxTorques,const double* pushVector,const dReal gravity,const dReal runTime,const dReal tstep,const dReal targetX,const dReal targetY,const int itSaveData,const std::string saveFile){

  endTime = runTime;
  simTime = 0.0;
  timeStep = tstep;

  dInitODE();
  world = dWorldCreate();
  space = dHashSpaceCreate(0);
  contactgroup = dJointGroupCreate(0);
  ground = dCreatePlane(space, 0, 0, 1, 0);
  dWorldSetGravity(world, 0, 0, gravity);

  createTargetObject(targetX,targetY);

  int nbData = static_cast<int>( ( endTime / timeStep ) / static_cast<double>(itSaveData) );

  robot = new R2DRobot(&world,controllers.size(),lengths,weights,radius,angleMin,angleMax,maxTorques,pushVector,controllers,itSaveData,nbData);

  dsFunctions   fn;
  fn.version = DS_VERSION;
  fn.start   = &setViewPoint;
  fn.step    = &loop;
  fn.stop = &stopSim;
  fn.path_to_textures = PATH_TO_TEXTURES;

  dsSimulationLoop(0, 0, 1280, 960, &fn);

 dWorldDestroy(world);
 dCloseODE();

 // NOTE: commenting the next three lines does not fix the problem !
 // it is the only place saveFile is used, except in the code of printData
 // I do not show the code of printData as commenting it does not change anything
 if (itSaveData>0){
    robot->printData(saveFile);
 }

 delete robot;

}

In the hope to find the unspecified variable (not that easy for a project with a lot of classes, some of them virtual), I played with the const parameters and observed the behavior of the robot. I reached a situation:

works fine all the time:

const std::string SAVEFILE = "C:\\Users\\Vincent\\Desktop\\tacit.txt";

crashes the program:

const std::string SAVEFILE = "C:\\Users\\Vincent\\Desktop\\ta";

Now the issue is, if I add a single line to the code of runExperiment (call to printf added):

printf("experiment.cpp - 1 \n");
robot = new R2DRobot(&world,controllers.size(),lengths,weights,radius,angleMin,angleMax,maxTorques,pushVector,controllers,itSaveData,nbData);

then both versions of SAVEFILE work fine and do give exactly similar results.

Now, if I delete the call to printf and add in the constructor of R2DRobot:

R2DRobot::R2DRobot(dWorldID * world, const int nbLinks, const double * lengths, const double * weights, const double radius,const double* angleMin,const double* angleMax,const double* maxTorques,const double* pushVector, std::vector<Controller*> controllers,int saveData,int nbData):
Robot(3*nbLinks+3,controllers),pushVector(pushVector),nbLinks(nbLinks),weights(weights),angleMin(angleMin),angleMax(angleMax),maxTorques(maxTorques),itSaveData(saveData){

printf("experiment.cpp - 1 \n");
// rest of the code

then the program crashes (if using the short version of SAVEFILE) but after printing "experiment.cpp -1" in the console.

Same thing if I move the call to printf to the constructor of Robot, the mother class of R2DRobot.


Solution

  • This might be manifestation that your program does not initialize variables properly. When string was shorter, compiler created certain memory layout, and variables created on a stack (or on a heap) had certain values. By pure luck, those values were something that seemed to work right for you.

    Now, since string has become longer, compiler has changed memory layout a little, and this led to slightly different layout. Now, these uninitialized variables might have slightly different values. It does not necessarily crash, but works differently.