【问题标题】:c++ / SFML - Memory leak shown in valgrind reportc++ / SFML - valgrind 报告中显示的内存泄漏
【发布时间】:2019-12-27 12:22:27
【问题描述】:

我有一段使用 SFML 反复绘制形状的小代码。它会突然中止并显示不同的错误消息,例如corrupted size vs. prev_size / Aborted (core dumped)munmap_chunk(): invalid pointer /Segmentation fault (core dumped)

我使用 valgrind 来追踪看起来像是内存泄漏的情况,但该报告对我来说相当神秘。尽管如此,据我了解,“肯定丢失:1 个块中的 4,096 个字节”并不是一个好兆头。最令人费解的是,当我通过valgrind运行它时它并没有中止。

我会继续调查,但如果有人能给我提示,那就太好了。

最好的问候,

MC

g++ -std=c++11 ./k.cpp -o ./k -Wfatal-errors -lsfml-graphics -lsfml-window -lsfml-system

#include "SFML/Graphics.hpp"
#include <iostream>
#include <math.h>
#include <random>
#include <stdio.h>
#include <string>

using namespace std;

struct point {
 double x;
 double y;
};

struct curve {
 int index;
 point centerPoint;
 double radius;
 sf::ConvexShape shape;
 sf::Text curveName;
 point curveNamePosition;
};

curve computeCurve(point centerPoint, double radius) {
 unsigned short numberOfPoints = 200;
 curve curve;
 curve.shape.setPointCount(numberOfPoints);
 curve.centerPoint.x = centerPoint.x;
 curve.centerPoint.y = centerPoint.y;
 curve.radius = radius;
 double alpha = 2 * M_PI / numberOfPoints;
 unsigned short a = 1;
 point point;

 for (unsigned short i = 0; i < numberOfPoints + 1; i++) {
   point.x = radius * (0.5 + cos(2 * a * alpha * i) / 2) * cos(alpha * i) +
             centerPoint.x;
   point.y = radius * sin(a * alpha * i) + centerPoint.y;
   curve.shape.setPoint(i, sf::Vector2f(point.x, point.y));
 };

 for (unsigned short i = 0; i < numberOfPoints - 1; i++) {
   point.x = radius * (0.5 + cos(2 * a * alpha * i) / 2) * cos(alpha * i) +
             centerPoint.x;
   point.y = -radius * sin(a * alpha * i) + centerPoint.y;
   curve.shape.setPoint(2 * numberOfPoints - i,
                        sf::Vector2f(point.x, point.y));
 };

 curve.shape.setOrigin(curve.centerPoint.x, curve.centerPoint.y);
 curve.shape.setPosition(curve.centerPoint.x, curve.centerPoint.y);
 curve.curveNamePosition.x = curve.centerPoint.x;
 curve.curveNamePosition.y = curve.centerPoint.y;
 curve.curveName.setString("Curve");
 curve.curveName.setPosition(curve.centerPoint.x, curve.centerPoint.y);

 return curve;
}

int main(int argc, char **argv) {
 const unsigned short windowWidth = 800;
 const unsigned short windowHeight = 800;

 sf::RenderWindow window(sf::VideoMode(windowWidth, windowHeight), "Demo",
                         sf::Style::Default); // Default / None // Fullscreen
 string myfontFileName = "./media/Arial.ttf";
 sf::Font myFont;

 if (!myFont.loadFromFile(myfontFileName)) {
   cout << "Could not find the font " << myfontFileName << endl;
 }

 sf::Event myEvent;
 sf::Clock curveClock;
 // Initialization
 point centerPoint;
 centerPoint.x = 300;
 centerPoint.y = 300;
 double radius = 200;
 curve mt = computeCurve(centerPoint, radius);
 mt.shape.setOutlineColor(sf::Color::Red);
 mt.shape.setFillColor(sf::Color(40, 140, 10, 127));
 mt.shape.setOutlineThickness(1.f);
 mt.curveName.setFont(myFont);
 mt.curveName.setCharacterSize(20);
 mt.curveName.setFillColor(sf::Color::White);

 std::random_device randomDevice;
 std::mt19937 seed(randomDevice());

 while (window.isOpen()) {
   while (window.pollEvent(myEvent)) {
     if (myEvent.type == sf::Event::EventType::Closed) {
       window.close();
     }
   }

   window.clear();

   if (curveClock.getElapsedTime().asMilliseconds() > 200.0f) {
     std::uniform_int_distribution<std::mt19937::result_type> rDistribution(
         10, 300);
     double radius = rDistribution(seed);

     std::uniform_int_distribution<std::mt19937::result_type> cDistribution(
         100, 300);
     centerPoint.x = cDistribution(seed);
     centerPoint.y = cDistribution(seed);

     mt = computeCurve(centerPoint, radius);
     mt.shape.setOutlineColor(sf::Color::Red);
     mt.shape.setFillColor(sf::Color(40, 140, 10, 127));
     mt.shape.setOutlineThickness(1.f);
     mt.curveName.setFont(myFont);
     mt.curveName.setCharacterSize(20);
     mt.curveName.setFillColor(sf::Color::White);
     curveClock.restart();
   }
   window.draw(mt.shape);
   window.draw(mt.curveName);
   window.display();
 }
 return EXIT_SUCCESS;
}

【问题讨论】:

  • 这是一个相当小的代码。只需系统地删除东西,直到找到导致它的原因。我没有看到任何动态分配(SFML 在内部执行的分配除外),所以看起来很奇怪,您会因此而发生内存泄漏。
  • 对不起,它已经被剥光了。但我发现了异常。它位于曲线本身的方程内。对于参数的 a=1 值,第二个循环第二次计算同一组点。所以每个点都在curve.shape中重复。我猜这对 SFML 来说太过分了。
  • 当您发布代码时,请注意有一些适当的缩进,以使其他人更容易阅读和理解代码。 (但也让您自己发现错误)并使用git 等工具更轻松地管理您的代码。大多数 IDE 可以为您做到这一点,或者您可以使用 clang-format 或类似 zed0.co.uk/clang-format-configurator 的网站
  • 感谢您指出。下次我会使用连贯的缩进。

标签: c++ memory-leaks valgrind sfml


【解决方案1】:

方程式的定义方式肯定有错误。如果有人感兴趣,这是一个更正的代码。

最好的问候,

MC

#include "SFML/Graphics.hpp"
#include <iostream>
#include <math.h>
#include <random>
#include <stdio.h>
#include <string>

using namespace std;

struct point {
  double x;
  double y;
};

struct curve {
  int index;
  point centerPoint;
  double radius;
  sf::ConvexShape shape;
  sf::Text name;
  point namePosition;
};

curve computeCurve(point centerPoint, double radius) {
  std::random_device randomDevice;
  std::mt19937 seed(randomDevice());
  std::uniform_int_distribution<std::mt19937::result_type> aDistribution(1, 4);
  int a = aDistribution(seed);

  unsigned short numberOfPoints = 100 * a;
  curve curve;
  curve.shape.setPointCount(numberOfPoints);
  curve.centerPoint.x = centerPoint.x;
  curve.centerPoint.y = centerPoint.y;
  curve.radius = radius;
  double alpha = 2 * M_PI / numberOfPoints;

  point point;

  for (unsigned short i = 0; i < numberOfPoints + 1; i++) {
    point.x = radius * (0.5 + cos(2 * a * alpha * i) / 2) * cos(alpha * i) +
              centerPoint.x;
    point.y = radius * sin(a * alpha * i) + centerPoint.y;
    curve.shape.setPoint(i, sf::Vector2f(point.x, point.y));
  };

  curve.shape.setOrigin(curve.centerPoint.x, curve.centerPoint.y);
  curve.shape.setPosition(curve.centerPoint.x, curve.centerPoint.y);

  curve.namePosition.x = curve.centerPoint.x;
  curve.namePosition.y = curve.centerPoint.y;
  curve.name.setString("Curve");
  curve.name.setPosition(curve.centerPoint.x, curve.centerPoint.y);

  return curve;
}
curve computeCardioid(point centerPoint, double radius) {
  double perimeter = 8 * radius;
  int numberOfPoints = max(floor(perimeter / 3), 20.0d);
  curve curve;
  curve.shape.setPointCount(numberOfPoints);
  curve.centerPoint.x = centerPoint.x;
  curve.centerPoint.y = centerPoint.y;
  curve.radius = radius;
  double alpha = 2 * M_PI / numberOfPoints;
  point point;

  for (unsigned short i = 0; i < numberOfPoints; i++) {
    point.x = 2 * radius * (1 - cos(alpha * i)) * cos(alpha * i) +
              curve.centerPoint.x;
    point.y = 2 * radius * (1 - cos(alpha * i)) * sin(alpha * i) +
              curve.centerPoint.y;
    curve.shape.setPoint(i, sf::Vector2f(point.x, point.y));
  };

  curve.shape.setOrigin(curve.centerPoint.x - 1.5 * radius,
                        curve.centerPoint.y);
  curve.shape.setPosition(curve.centerPoint.x, curve.centerPoint.y);

  curve.namePosition.x = curve.centerPoint.x;
  curve.namePosition.y = curve.centerPoint.y;
  curve.name.setString("Card");
  curve.name.setPosition(curve.centerPoint.x, curve.centerPoint.y);

  return curve;
}
int main(int argc, char **argv) {
  const unsigned short windowWidth = 800;
  const unsigned short windowHeight = 800;

  sf::RenderWindow window(sf::VideoMode(windowWidth, windowHeight), "Demo",
                          sf::Style::Default); // Default / None // Fullscreen
  string myfontFileName = "./media/Arial.ttf";
  sf::Font myFont;

  if (!myFont.loadFromFile(myfontFileName)) {
    cout << "Could not find the font " << myfontFileName << endl;
  }

  sf::Event myEvent;
  sf::Clock curveClock;
  // Initialization
  point centerPoint;
  centerPoint.x = 300;
  centerPoint.y = 300;
  double radius = 200;

  curve curve = computeCurve(centerPoint, radius);
  curve.shape.setOutlineColor(sf::Color::Red);
  curve.shape.setFillColor(sf::Color(40, 140, 10, 127));
  curve.shape.setOutlineThickness(1.f);
  curve.name.setFont(myFont);
  curve.name.setCharacterSize(20);
  curve.name.setFillColor(sf::Color::White);

  random_device randomDevice;
  mt19937 seed(randomDevice());

  while (window.isOpen()) {

    while (window.pollEvent(myEvent)) {
      if (myEvent.type == sf::Event::EventType::Closed) {
        window.close();
      }
    }

    window.clear();

    if (curveClock.getElapsedTime().asMilliseconds() > 1000.0f) {
      uniform_int_distribution<mt19937::result_type> rDistribution(10, 300);
      double radius = rDistribution(seed);

      point centerPoint;
      uniform_int_distribution<mt19937::result_type> cDistribution(100, 300);
      centerPoint.x = cDistribution(seed);
      centerPoint.y = cDistribution(seed);
      curve = computeCurve(centerPoint, radius);
      curve.shape.setOutlineColor(sf::Color::Red);
      curve.shape.setFillColor(sf::Color(40, 140, 10, 127));
      curve.shape.setOutlineThickness(1.f);
      curve.name.setFont(myFont);
      curve.name.setCharacterSize(20);
      curve.name.setFillColor(sf::Color::White);
      curveClock.restart();
    }

    window.draw(curve.shape);
    window.draw(curve.name);
    window.display();
  }

  return EXIT_SUCCESS;
}

【讨论】:

  • 回答你自己的问题很棒。为了改进答案,如果您指出哪个更改解决了您的问题,那就太好了。没有它,未来可能遇到相同问题的读者将需要区分这两个代码,并且在您的情况下,这尤其复杂,因为您更改了许多内容(包括命名和其他内容)。
  • 第二次循环计算曲线各点坐标时出现错误。第二个循环是多余的,并且第二次计算整个点集。画线时,我猜 SFML 会因为一个形状获得两次相同的点而感到不安。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-09-17
  • 2015-04-05
  • 2017-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多