2014-04-19 2 views
2

가 이해가 안 컴파일하고 오류없이 실행 않습니다왜이 코드는이 코드를 컴파일하는 이유

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

이 내가 코드를 컴파일하는 방법입니다 다시 실행하면 세그멘테이션 오류가 발생합니다. 우분투 14.04에서 Eigen 3.2.0-8을 사용하고 있습니다.

권장 사항.

$ 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) 
+0

valgrind를 실행할 때'cout'을 주석 처리 했습니까? 컴파일러는 오작동하는 코드를 최적화 할 가능성이 있습니다. – dasblinkenlight

+0

Eigen의 표현 템플릿과 오버로드 된 연산자가 많이 사용 된 것으로 의심되는 이유는 valgrind가이 코드가 배열의 끝을 넘어서 씁니다. –

답변

3

어설 션을 사용하지 않고 컴파일 한 것으로 의심됩니다.

Eigen은 쉼표로 구분 된 목록으로 행렬을 초기화 할 수 있도록 operator<<을 오버로드합니다. (이것은 또한 쉼표 연산자 뒤에서 숨어 있음을 의미합니다). 쉼표로 구분 된 항목 목록에는 숫자가 포함될 수 있지만 벡터 나 다른 행렬도 포함될 수 있습니다.

이러한 유연성은 비용 부담으로 발생합니다. Eigen은 콤마로 구분 된 목록에 항목이 너무 많거나 너무 적음을 컴파일 타임에 알 수 없습니다. 대신 실행시 너무 많은 항목이나 너무 적은 항목을 감지하여 eigen_assert을 통해 불평합니다. 어설 션을 사용하지 않고 컴파일 한 경우 항목의 지나치게 가득 찬 목록이 SIGABRT에서 정의되지 않은 동작으로 변경됩니다.

이런 종류의 문제는 정의되지 않은 동작으로 항상 발생합니다. 진술을 추가하면 마술없이 오류없이 코드를 실행할 수 있습니다. 사물이 괜찮다는 신호로 삼지 마십시오. 방금 뛰었습니다. 정의되지 않은 동작은 항상 잘못되었습니다. 어떤 경우에는 "작동"한다고해서 다음에 프로그램을 사용할 때 코드가 하드 드라이브를 다시 포맷하지 않는다는 것을 의미하지는 않습니다.

+0

'g ++ test_eigen.cpp -o test_eigen -I/usr/include/eigen3 -O3'로 컴파일하고 실행합니다; '쉼표 이니셜 라이저 (연산자 <<)에 전달 된 행이 너무 많습니다. Eigen 어설 션을 사용하지 않도록 설정하면 오류를 발생시키지 않고 실행 한 근본 원인이됩니다. –

+0

Eigen을 사용하면 프로그램을 철저히 테스트 한 후에 어설 션을 비활성화해야 제대로 작동합니다. –

+0

그리고 변경을 할 때마다 assertions를 다시 활성화하는 것을 잊지 마십시오.;) [실제로는 assertions로 컴파일하고 assert없이 버전을 빌드하면서 테스트 세트를 실행하는 빌드 설정을해야합니다.] –

1

Why does this code compile?

컴파일러는 컴파일시에 operator<<에 전달 얼마나 많은 요소를 알 수 없기 때문에 여기 (주석 std::cout와) Valgrind의 출력이다. 이 정보는 런타임에만 제공됩니다.

+0

이 경우를 제외하고 컴파일 타임에 알려져 있습니다. – juanchopanza

+0

'연산자 <<'는이 경우 스트림 추출 연산자가 아닙니다. 입력은 쉼표로 구분 된 목록에서 나옵니다 (쉼표 연산자를 오버로드하는 이점이 있습니다). –

+0

@DavidHammen, 결코 그런 말은하지 않았습니다. :) – Shoe

5

할당 된 데이터 구조의 경계를 넘어서는 쓰기 (예 : 할당 된 5x3에 5x5 행렬 쓰기)는 정의되지 않은 동작입니다. 충돌이있을 수도 있고 아닐 수도 있지만, 불행히도 눈에 보이지 않는 오류없이 완료 될 수 있습니다.

valgrind 코드를 실행하여 설명한 문제와 유사한 메모리 문제를 찾아냅니다.

+0

이것은 올바른 대답이 아닙니다. –

+0

@DavidHammen 제발 편집을 정교하게 제안하십시오. – dasblinkenlight

+0

코어 덤프는'eigen_assert'에서 발생합니다. 그는 그것을보아야한다. –