为什么这段代码会编译

时间:2014-04-19 11:40:22

标签: c++ eigen

我不明白为什么这段代码会编译并运行而不会出错:

#include <iostream>
#include <stdio.h>
#include <Eigen/Dense>

int
main (int argc, char *argv[])
{
  typedef Eigen::Matrix<double, 5, 3/*FIXME: Should be 5*/> Matrix5;

  Matrix5 test;
  test << 2,0,0,1,1, 
          0,2,0,1,1,
          0,0,2,2,2,
          0,1,2,0,0,
          0,1,1,0,0; // We filled a 5*5 matrix in a 5*3 matrix

  //std::cout << "Test matrix:\n" << test << std::endl;
  return (0);
}

这是我编译代码的方式:

g++ test_eigen.cpp -o test_eigen -I/usr/include/eigen3 -O3 -DEIGEN_NO_DEBUG

取消注释std::cout,编译,再次运行,您将收到分段错误。 我在Ubuntu 14.04上使用Eigen 3.2.0-8。

如建议的那样;这是Valgrind的输出(std::cout注释):

$ valgrind ./test_eigen
==12380== Memcheck, a memory error detector
==12380== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==12380== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==12380== Command: ./test_eigen
==12380== 
==12380== 
==12380== HEAP SUMMARY:
==12380==     in use at exit: 0 bytes in 0 blocks
==12380==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==12380== 
==12380== All heap blocks were freed -- no leaks are possible
==12380== 
==12380== For counts of detected and suppressed errors, rerun with: -v
==12380== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

3 个答案:

答案 0 :(得分:5)

写过数据结构的已分配边界(例如,将5x5矩阵写入分配的5x3)是未定义的行为。它可能会也可能不会崩溃,不幸的是,甚至可能会在没有明显错误的情况下运行完毕。

使用valgrind运行代码,以查明与您描述的内容类似的内存问题。

答案 1 :(得分:3)

我怀疑你编译时禁用了断言。

Eigen重载operator<<以使用逗号分隔列表初始化矩阵。 (请注意,这也意味着在幕后隐藏逗号运算符)。该逗号分隔的项目列表可以包含数字,但它也可以包含一个向量或另一个矩阵。

这种灵活性需要付出代价。 Eigen在编译时无法判断逗号分隔列表包含太多或太少的项目。它反而在运行时检测到太多/太少的项目并通过eigen_assert进行投诉。如果编译时禁用了断言,则可以让过度完整的项目列表从SIGABRT变为未定义的行为。

这种事情一直都是以未定义的行为发生的,添加一个语句会让代码无错误地运行。不要将此视为事情没问题的标志。它碰巧跑了。未定义的行为总是很糟糕。仅仅因为它&#34;工作&#34;在某些情况下,并不意味着您的代码在下次使用该程序时不会重新格式化您的硬盘。

答案 2 :(得分:1)

  

为什么这段代码会编译?

因为编译器无法知道在编译时传递给operator<<的元素数量。该信息仅在运行时可用。