修复C ++中的分割错误
我正在为Windows和Unix编写一个跨平台的C ++程序。 在窗口一侧,代码将编译并执行没有问题。 在Unix方面,它会编译,但是当我尝试运行它时,我得到了一个分段错误。 我最初的直觉是指针有问题。
什么是好的方法来find和修复分段错误?
-
用
-g
编译你的应用程序,然后在二进制文件中有debugging符号。 -
使用
gdb
打开gdb控制台。 -
使用
file
并将其应用程序的二进制文件传递给控制台。 -
使用
run
并传入应用程序需要启动的任何参数。 -
做一些事情导致分段错误 。
-
在
gdb
控制台中键入bt
以获得分段错误的堆栈跟踪。
有时候,崩溃本身并不是问题的真正原因 – 也许是早期的记忆被粉碎了,但是贪污腐败却需要一段时间才能显现出来。 检查valgrind ,它有很多检查指针问题(包括数组边界检查)。 它会告诉你问题在哪里开始 ,而不仅仅是发生崩溃的那一行。
在问题出现之前,尽量避免它:
- 尽可能经常编译和运行您的代码。 定位故障部分将更容易。
- 尝试封装低级/容易出错的例程,这样你很less需要直接使用内存(注意程序的模型化)
- 维护一个testing套件。 总结一下当前的工作,什么是没有更多的工作等,将帮助你找出问题所在( 升压testing是一个可能的解决scheme,我不使用它自己,但文档可以帮助了解什么样的信息必须显示)。
使用适当的工具进行debugging。 在Unix上:
- GDB可以告诉你程序崩溃的地方,并让你看到在什么情况下。
- Valgrind将帮助您检测许多与内存相关的错误。
-
使用海湾合作委员会,你也可以使用海湾合作委员会和叮当的mudflap你可以使用地址/内存消毒剂 。 它可以检测到Valgrind没有的错误,性能损失更轻。
最后我会推荐平常的事情。 你的程序可读性越高,可维护性越强,清晰整洁,最容易debugging。
在Unix上,你可以使用valgrind来查找问题。 它是免费的,function强大。 如果你想自己做,你可以重载新的和删除操作符来设置一个configuration,在每个新的对象之前和之后你有1个字节的0xDEADBEEF
。 然后跟踪每次迭代发生的事情。 这可能无法抓住所有的东西(你甚至不能保证触摸这些字节),但是它在Windows平台上过去对我来说很合适。
是的,指针有问题。 很可能你正在使用一个没有被正确初始化的东西,但是也有可能是你用双重释放或者其他方式搞乱了你的内存pipe理。
为了避免未初始化的指针作为局部variables,尽可能迟的尝试声明它们,最好(并不总是可能的),当它们可以用一个有意义的值初始化。 通过检查代码,说服他们在使用之前会有价值。 如果你遇到困难,将它们初始化为一个空指针常量(通常写为NULL
或0
)并检查它们。
要避免未初始化的指针作为成员值,请确保它们已在构造函数中正确初始化,并在复制构造函数和赋值运算符中正确处理。 尽pipe可以进行其他初始化,但不要依赖init
函数进行内存pipe理。
如果您的类不需要复制构造函数或赋值运算符,则可以将它们声明为私有成员函数,而不用定义它们。 这会导致编译器错误,如果他们明确或隐式地使用。
适用时使用智能指针。 这里最大的好处是,如果你坚持使用它们,你就可以完全避免写入delete
而且不会有任何东西被删除。
尽可能使用C ++string和容器类,而不要使用C风格的string和数组。 考虑使用.at(i)
而不是[i]
,因为这会迫使边界检查。 看看你的编译器或库是否可以设置为检查[i]
上的界限,至less在debugging模式下。 分段错误可能由缓冲区溢出引起,这些溢出将垃圾写入完美的指针。
做这些事情将大大降低分段错误和其他内存问题的可能性。 他们无疑将无法解决所有问题,这就是为什么你应该不时地使用valgrind,当你没有问题时,valgrind和gdb。
我不知道用什么方法来解决这个问题。 我不认为有可能为手头的问题提出一个意见,那就是你的程序的行为是不确定的(我不知道SEGFAULT是不是由某种UB引起的) 。
有各种各样的“方法论”来避免这个问题发生。 一个重要的是RAII。
除此之外,你只需要把最好的精神能量扔在它上面。