6

C++ プログラムで segfault の奇妙なケースに直面しました。小さなコードで再現できますが、なぜそれが起こっているのかわかりません。コードは次のとおりです。

a.hpp :

#pragma once
#include <boost/shared_ptr.hpp>
#include "b.hpp"

class A
{
    public:
        explicit A ();    
    private:
        std::string str1_;
        B b_;
        std::string str2_;
};

typedef boost::shared_ptr< A > A_ptr;

a.cpp

#include "a.hpp"
A::A () {}

b.hpp

#pragma once
#include <string>

class B
{   
    public:
        B ();
    private:
        std::string str1_;
};   

b.cpp

#include "b.hpp"    
B::B () {}

main.cpp

#include "a.hpp"

int main ()
{
    A_ptr a( new A() );
}

make の出力:

% make
g++ -Wall -Wextra -g -fno-inline -O0   -c -o main.o main.cpp
g++ -Wall -Wextra -g -fno-inline -O0   -c -o a.o a.cpp
g++ -Wall -Wextra -g -fno-inline -O0   -c -o b.o b.cpp
g++  -o main main.o a.o b.o 
dsymutil main

これで問題なく動作します。B b_から(の宣言b_)を削除し、 (ビルドをトリガーするために)a.hpp保存して、再度実行します。a.cppmake

% make
g++ -Wall -Wextra -g -fno-inline -O0   -c -o a.o a.cpp
g++  -o main main.o a.o b.o 
dsymutil main

そして、次のようにセグメンテーション違反をプログラムします。

(gdb) bt
#0  0x00007fff97f106e5 in std::string::_Rep::_M_dispose ()
#1  0x00007fff97f10740 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string ()
#2  0x0000000100001091 in A::~A (this=0x1001008b0) at a.hpp:8
#3  0x00000001000011da in boost::checked_delete<A> (x=0x1001008b0) at checked_delete.hpp:34
#4  0x0000000100001026 in boost::detail::sp_counted_impl_p<A>::dispose (this=0x1001008d0) at sp_counted_impl.hpp:78
#5  0x0000000100000d9a in boost::detail::sp_counted_base::release (this=0x1001008d0) at sp_counted_base_gcc_x86.hpp:145
#6  0x0000000100000dd4 in boost::detail::shared_count::~shared_count (this=0x7fff5fbff568) at shared_count.hpp:305
#7  0x0000000100000f2b in boost::shared_ptr<A>::~shared_ptr (this=0x7fff5fbff560) at shared_ptr.hpp:159
#8  0x0000000100000aac in main () at main.cpp:5

Imake cleanmakeの場合、プログラムは segfault なしで実行されます。クラスのメンバーが削除され、プロジェクトがクリーンなしでビルドされた場合にプログラムのセグメンテーション違反が発生する理由を理解してください。

4

1 に答える 1

11

の 2 回目の実行時make:

% make
g++ -Wall -Wextra -g -fno-inline -O0   -c -o a.o a.cpp
g++  -o main main.o a.o b.o 
dsymutil main

あなたはただ再コンパイルしていa.cppます。次に、make の前回の実行で生成された残りのオブジェクト ファイルにリンクします。これにより、 ( に含まれる)main.cppの古い定義が使用されますが、 ( )の新しいオブジェクト ファイルは新しい定義が使用されるため、クラッシュします。class Aa.hclass Aa.o

(具体的には、newclass Aはサイズが異なるため、スタック上に確保する必要があるメモリmain()が異なり、メンバー変数の配置も異なります)。

これは明らかに、 の依存関係の問題ですMakefile

を実行するmake clean/makeと、すべてのファイルが同じ正しい定義を使用しclass A、すべてが正しく機能します。

于 2012-10-17T21:10:48.140 に答える