更新类的字段后出现分段错误

时间:2013-03-21 19:13:01

标签: c++ segmentation-fault

我在main函数中构建了一些类。它们在主要返回后都被解构,因为它们是在局部变量中定义的。但是我注意到了一个我想避免的奇怪事件。如果我更改其中一个类的内存布局(通过添加或更改字段),然后在链接之前仅重新编译修改后的类,我会得到分段错误或无效指针(取决于我对程序所做的更改) 。如果我也重新编译主文件,则没有错误。

我很确定会发生这种情况,因为当我在主文件中包含标题时,它假定为每个类分配了一定量的内存,但是自main.o编译后这个值已经改变了,因此,它会在程序关闭时解析对象时查找不存在的内存。

虽然重新编译主文件目前不是问题,但我担心随着项目的增长,我将在其他文件中遇到这种情况,并且每次重新编译它们以避免错误是不可取的。有没有一种简单的方法来避免这些错误?

4 个答案:

答案 0 :(得分:1)

更有可能的是,某些类成员(例如构造函数和/或析构函数)被内联而某些类成员没有内联,并且每个集合将使用与对象指针不同的偏移量来查找特定成员。

考虑使用mkdep之类的东西来生成具有正确的源到头依赖关系的makefile,这样更改标头会导致包含该标头的所有文件被重新编译。

或者,您可以选择在类的源文件中保留所有类成员定义(包括构造函数,复制构造函数和赋值运算符 - 在这种情况下不应该自动生成) ,有效地禁止内联。在大多数情况下,这应足以防止出现此问题,但这会带来(轻微)性能成本。 (如果您将数据成员添加到类中,这将无法帮助您 - 从而增加对象的大小 - 除非您另外使用pimpl idiom,这会为所有数据成员访问添加间接级别。 )

答案 1 :(得分:1)

没有。如果您的类的布局发生更改,则您需要重新编译使用该类的任何单元。

答案 2 :(得分:0)

在阅读了cdhowie的回答之后,我开始研究mkdep,但是看起来这样的程序已被弃用,并且已经被编译器标志所取代,它们做同样的事情。我已经包含了我的makefile的主体,它编译主程序(srcpath中的代码)和测试(testpath中的代码),然后运行测试。在此期间创建了两个单独的依赖文件,一个用于main,另一个用于测试。

src = $(shell cd $(srcpath); find ./ -name "*.cpp")
testsrc = $(shell cd $(testpath); find ./ -name "*.cpp")
obj = $(src:%.cpp=%.o)
testobj = $(testsrc:%.cpp=%.o)
head = $(shell cd $(srcpath); find ./ -name "*.h")
testhead = $(shell cd $(testpath); find ./ -name "*.h")
skip_files = ./main.o

makedep = $(shell $(cpp) $(cflags) -MM -MT '$(patsubst $(srcpath)%.cpp, $(objpath)%.o, $(file))' $(file) >> .depend)
makedeptest = $(shell $(cpp) $(cflags) -MM -MT '$(patsubst $(testpath)%.cpp, $(testobjpath)%.o, $(file))' $(file) >> .dependtest)

all: main Test

Test: .dependtest $(addprefix $(testobjpath),$(testobj))
    @echo "Linking Tests"
    @$(cpp) $(lflags) -o $(testbin) $(addprefix $(testobjpath), $(testobj)) $(addprefix $(objpath), $(filter-out $(skip_files),$(obj)))
    @./$(testbin)

.dependtest: $(addprefix $(testpath), $(testsrc)) $(addprefix $(testpath), $(testhead))
    $(shell rm -f .dependtest)
    $(foreach file,$(addprefix $(testpath), $(testsrc)), $(makedeptest))

$(addprefix $(testobjpath), %.o): $(addprefix $(testpath), %.cpp)
    $(cpp) $(cflags) -c -o $@ $<

main: .depend $(addprefix $(objpath), $(obj))
    @echo "Linking Program"
    @$(cpp) $(lflags) -o $(bin) $(addprefix $(objpath),$(obj))

.depend: $(addprefix $(srcpath), $(src)) $(addprefix $(srcpath), $(head))
    $(shell rm -f .depend)
    $(foreach file, $(addprefix $(srcpath), $(src)), $(makedep))

$(addprefix $(objpath), %.o): $(addprefix $(srcpath), %.cpp)
    $(cpp) $(cflags) -c -o $@ $<

clean:
    -rm $(testbin) $(bin) $(addprefix $(objpath),$(obj)) $(addprefix $(testobjpath),$(testobj))

-include .depend
-include .dependtest

答案 3 :(得分:-3)

使用IDE而不是在命令行进行编译。