【问题标题】:C++ string and memory managementC++ 字符串和内存管理
【发布时间】:2013-04-03 06:56:25
【问题描述】:

我现在正在从事一个涉及控制模拟机械臂的相当复杂的项目。 我完成了该项目的第一个版本,它工作正常。 我刚刚添加了一些新代码,这些代码在每次迭代时收集有关系统的一些信息,将其保存在一些数组中,最后将所有内容打印到一个文件中以供以后分析。

现在,真正奇怪的事情正在发生。如果我将保存数据的文件定义如下:

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

一切正常,与我添加新代码之前完全相同(加上保存数据)。

但如果我定义如下:

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

然后系统以另一种方式运行。不会崩溃,但机械臂的移动方式不同。

我试图注释所有使用 SAVEFILE 的代码,甚至是与数据保存相关的任何新代码,但问题仍然存在。

我知道,只有这些信息,任何人都不太可能告诉我出了什么问题,但是有人会建议看什么方向吗? 认为长字符串会覆盖其他变量的值是否有意义?怎么可能?我可能已经破坏了一些干净的 C++ 编程指南?

有些阵列行为不端听起来可能,这是我检查的第一件事。我想它应该来自保存数据的数组,因为它们是唯一的新数组。问题是,即使我注释了所有相应的代码,也没有任何变化。

我尝试提供有关我的代码的更多信息。这里我第一次使用 SAVEFILE(runExperiment 函数的最后一个参数)

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

这里是函数的代码:

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;

}

为了找到未指定的变量(对于一个有很多类的项目来说并不容易,其中一些是虚拟的),我使用了 const 参数并观察了机器人的行为。我遇到了一个情况:

一直运行良好:

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

使程序崩溃:

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

现在的问题是,如果我在 runExperiment 的代码中添加一行(添加了对 printf 的调用):

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

那么 SAVEFILE 的两个版本都可以正常工作,并且确实给出了完全相同的结果。

现在,如果我删除对 printf 的调用并添加到 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

然后程序崩溃(如果使用 SAVEFILE 的短版本)但在控制台中打印“experiment.cpp -1”之后。

如果我将对 printf 的调用移至 Robot 的构造函数,即 R2DRobot 的母类。

【问题讨论】:

  • 问题可能出在您的业务逻辑中。通过使用std::string,您实际上是在遵循良好的编程习惯。如果内存不足,则会抛出异常。但是,正如您所怀疑的那样,不会发生错误的覆盖。
  • 可能是写入“附近”变量中定义的数组或缓冲区的溢出。
  • 对我来说,这听起来像是程序的某些 other 部分从它不应该访问的内存区域读取。从数组或类似的东西中读取时,您可能会越界。您是否尝试过在检查内存使用情况的工具(例如 valgrind)中运行您的程序?
  • @iammilind :业务逻辑是什么意思?
  • @roger_rowland :这是我的第一个猜测,但是当 SAVEFILE 的长度减少时,为什么这些相同的数组不会表现得不好?这真的让我很困惑。

标签: c++ string memory ode-library


【解决方案1】:

这可能表明您的程序没有正确初始化变量。当字符串较短时,编译器会创建特定的内存布局,并且在堆栈(或堆)上创建的变量具有特定的值。幸运的是,这些价值观似乎适合你。

现在,由于字符串变长了,编译器稍微改变了内存布局,这导致布局略有不同。现在,这些未初始化的变量的值可能略有不同。它不一定会崩溃,但工作方式不同。

【讨论】:

  • 只是为了确保我得到它......所以我的下一步应该是检查我是否有未初始化的变量?所以我声明了一些东西,但忘了给 ?
  • 没错。如果你找不到类似的东西,那么一定有一些东西在你不知情的情况下改变了你的变量。
  • 例如,在声明dsFunctions fn; 之后,您填写了fn 的某些字段,但我不相信您会填写全部。在这种情况下,它们将保持未初始化状态(包含垃圾),这将造成问题
  • 哦,这是一个很好的观点。例如,这件事已经给我带来了一些麻烦,因为我没有填充现场停止。将对此进行调查。
  • 确实,缺少一个字段(命令:opende.sourceforge.net/docs/structds_functions.html)。不幸的是,更正此问题并没有解决问题。
【解决方案2】:

但是有没有人给点建议看看什么方向

不幸的是,这些信息确实不够。也许,您可以尝试使用valgrind 或类似工具来分析您的代码。


认为长字符串会覆盖其他变量的值是否有意义?怎么可能?

不,这不是一个长字符串。它甚至不接近长字符串。如果字符串太长,则会出现无效长度异常。


我可能已经破坏了一些干净的 C++ 编程指南

信息不足。使用std::string 很好,甚至被推荐。

问题出在其他地方。对我来说,这听起来像是未定义的行为。

【讨论】:

    【解决方案3】:

    runExperiment 带有全局变量的参数的高度数告诉您,您可能需要更高级别的对象来包装和组织它。在尝试为此类对象编写构造函数时,您可能会看到并纠正错误/未初始化变量的问题,这将防止未定义的行为。

    【讨论】:

      猜你喜欢
      • 2010-10-11
      • 2011-10-22
      • 2021-07-28
      • 2013-06-17
      • 2017-01-31
      • 2014-10-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多