std::vector<std::string> 崩溃

7
这个问题是我之前提出的一个问题的延续,详见我的问题
下面是有问题的代码。
a.h:
#include <string>
#include <vector>

std::vector<std::string> foo();

a.cpp

#include "a.h"

std::vector<std::string> foo()
{
   std::vector<std::string> v;
   return v;
}

最后是main.cpp文件:

#include "a.h"
#include <iostream>

int main()
{
    std::vector<std::string> s = foo();

    return 0;
}

以下是编译过程(main.cpp 使用 STL 调试标志进行编译):
g++ -c a.cpp
g++ -D_GLIBCXX_DEBUG main.cpp a.o

运行 a.out 时,进程崩溃:
Core was generated by `./a.out'.
Program terminated with signal 11, Segmentation fault.
#0  0x00007fe355998c43 in __gnu_debug::_Safe_iterator_base::_M_detach_single() () from /usr/lib64/libstdc++.so.6
(gdb) bt
#0  0x00007fe355998c43 in __gnu_debug::_Safe_iterator_base::_M_detach_single() () from /usr/lib64/libstdc++.so.6
#1  0x00007fe355999ebc in __gnu_debug::_Safe_sequence_base::_M_detach_all() () from /usr/lib64/libstdc++.so.6
#2  0x0000000000400cac in __gnu_debug::_Safe_sequence_base::~_Safe_sequence_base() ()
#3  0x0000000000400cc6 in __gnu_debug::_Safe_sequence<std::__debug::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::~_Safe_sequence() ()
#4  0x0000000000400ce7 in std::__debug::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::~vector() ()
#5  0x0000000000400c35 in main ()

我的GCC:
Using built-in specs.
Target: x86_64-suse-linux
Configured with: ../configure --prefix=/usr --infodir=/usr/share/info --mandir=/usr/share/man --libdir=/usr/lib64 --libexecdir=/usr/lib64 --enable-languages=c,c++,objc,fortran,obj-c++,java,ada --enable-checking=release --with-gxx-include-dir=/usr/include/c++/4.4 --enable-ssp --disable-libssp --with-bugurl=http://bugs.opensuse.org/ --with-pkgversion='SUSE Linux' --disable-libgcj --disable-libmudflap --with-slibdir=/lib64 --with-system-zlib --enable-__cxa_atexit --enable-libstdcxx-allocator=new --disable-libstdcxx-pch --enable-version-specific-runtime-libs --program-suffix=-4.4 --enable-linux-futex --without-system-libunwind --with-arch-32=i586 --with-tune=generic --build=x86_64-suse-linux
Thread model: posix
gcc version 4.4.1 [gcc-4_4-branch revision 150839] (SUSE Linux)
2个回答

13
你的问题在于只给`a.cpp`传递了参数`-D_GLIBCXX_DEBUG`。该标志位会向STL结构添加额外的调试信息,因此在整个项目中必须一致使用。否则,不同的文件将对`std::vector`和`std::string`的内存布局存在分歧,导致未定义的行为(在你的情况下是崩溃)。

这也是我所理解的。那么,您如何评论对我的问题https://dev59.com/12445IYBdhLWcg3wpLx_的回答?是我误解了答案还是我的问题不清楚/正确? - dimba
2
要明确的是,通常情况下,应该一次性设置标志,并将其一致地应用于您希望编译的整个文件集。 - Matthieu M.
@Matthieu,您能否也参考上面的第一个评论? - dimba
1
@dimba,我对 stringvector 的 G++ 实现不够熟悉,无法确切地评论其表示方式的变化;但是,你的实验表明了它确实存在。话虽如此,我对你链接的 G++ 文档的解读表明,尽管 std::string 可以在调试和发布模式之间安全地传递,但 std::vector 没有这样的保证。 - bdonlan
1
一个小细节更正:根据GCC文档,使用方式必须在所有访问给定容器对象的文件中保持一致,但是其他文件(可能还包含单独一组容器对象)可以使用不同的标志进行编译。他们花了一些功夫来实现这个。 - Brooks Moses

1
在您之前的问题中,您引用了GCC文档:http://gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt03ch17s04.html。该文档指出,GCC libstdc++“支持每个用户的重新编译”,并将其定义如下:
逐次重新编译:用户必须重新编译应用程序的部分内容和其所依赖的C++库,以及与这些容器交互的任何其他代码,以便进行调试。这意味着访问特定标准容器实例的一组翻译单元可以被编译为发布模式(不检查)或调试模式(完全检查),但必须以相同的方式编译;不需要重新编译不看到该标准容器实例的翻译单元A。这也意味着在发生部分重新编译时不存在的功能,即编译在发布模式下的包含特定实例(比如std::vector)的翻译单元A可以链接到编译在调试模式下的包含相同实例的翻译单元B。虽然这种行为严格来说违反了一个定义规则,但是这种能力在实践中非常重要。libstdc++调试模式支持此级别的重新编译。
关于每个单元编译,您正在尝试执行的操作,它说:
我们认为,如果我们打算提供安全迭代器、保持程序语义不变并且在发布模式下不降低性能,事实上不可能实现这种重新编译级别。

因此,我之前对你的问题的回答并不完全准确,我很抱歉。我已经添加了一个附录来纠正它,并提供了一个有用的建议,关于如何解决那里的多库问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接