我收到用户报告我开发的库中存在段错误的错误报告。
错误代码的最小示例是:
#include <map>
#include <string>
#include <iostream>
void f(std::map<std::string, std::string> m = {})
{
std::cout << m.size() << "\n";
for (const auto& s: m) {
std::cout << s.first << "->" << s.second <<"\n";
}
}
int main()
{
f();
}
使用 GCC 编译时(我测试了 4.8.2 和 4.7.3),它会正确打印 0作为容器的大小,但循环内的段错误(根本不应该执行)。
但是,我可以通过将声明更改为修复问题:
void f(std::map<std::string, std::string> m = std::map<std::string, std::string>{})
复制map也可以:
void f(std::map<std::string, std::string> mx = {})
{
auto m = mx;
std::cout << m.size() << "\n";
for (const auto& s: m) {
std::cout << s.first << "->" << s.second <<"\n";
}
}
将参数更改为 const std::map<...>&也可以。
GCC 4.9.1 工作正常。
Clang 也可以很好地编译和运行代码。 (即使使用与失败 gcc 4.8.2 相同的 libstdc++)
工作示例:http://coliru.stacked-crooked.com/a/eb64a7053f542efd
map 在函数内部肯定不是有效状态(详情如下)。 它看起来像一个 GCC(或 libstdc++)错误,但我想确保我没有在这里犯一些愚蠢的错误。 很难相信这样的错误会在 gcc 中保留至少 2 个主要版本。
所以我的问题是:初始化默认的方式是std::map参数错误(以及我的代码中的错误)还是 stdlibc++ 中的错误(或 gcc )?
我不是在寻找解决方法(因为我知道如何使代码工作) 当集成到应用程序中时,有问题的代码在某些计算机上可以正常执行(即使使用 gcc 4.8.2 编译),而在某些计算机上却不能。
我编译它使用:
g++-4.8.2 -g -Wall -Wextra -pedantic -std=c++11 /tmp/c.cpp -o /tmp/t
来自 gdb 的回溯:
#0 std::operator<< <char, std::char_traits<char>, std::allocator<char> > (__os=..., __str=...) at /usr/src/debug/sys-devel/gcc-4.8.2/build/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/basic_string.h:2758
#1 0x0000000000400f36 in f (m=std::map with 0 elements) at /tmp/c.cpp:9
#2 0x0000000000400fe0 in main () at /tmp/c.cpp:15
/tmp/c.cpp:9 是带有 std::cout << ... 的行
ASAN 报告:
AddressSanitizer: SEGV on unknown address 0xffffffffffffffe8
这似乎是 nullptr - 8
valgrind 显示:
==28183== Invalid read of size 8
==28183== at 0x4ECC863: std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (in /usr/lib64/gcc/x86_64-pc-linux-gnu/4.8.2/libstdc++.so.6.0.18)
==28183== by 0x400BD5: f(std::map<std::string, std::string, std::less<std::string>, std::allocator<std::pair<std::string const, std::string> > >) (c.cpp:9)
==28183== by 0x400C7F: main (c.cpp:15)
==28183== Address 0xffffffffffffffe8 is not stack'd, malloc'd or (recently) free'd
查看 map 的内部状态表明代码确实必须失败:
std::map::begin()在 libstdc++ 中返回
this->_M_impl._M_header._M_parent
从它的内部表示来看,std::map::end()返回:
&this->_M_impl._M_header
gdb 显示:
(gdb) print m._M_t._M_impl._M_header
$5 = {_M_color = std::_S_red, _M_parent = 0x0, _M_left = 0x7fffffffd6d8, _M_right = 0x7fffffffd6d8}
(gdb) print &m._M_t._M_impl._M_header
$6 = (std::_Rb_tree_node_base *) 0x7fffffffd6a8
begin() 的值和 end()与标准规定的空 begin() 不同(std::map 为 nullptr) .
最佳答案
看起来像 bug was fixed in 4.8.3/4.9.0 ,具有类似示例和段错误的错误报告说:
The attached minimal testcase has the following function with default-constructed default argument:
void do_something( foo f = {} ) { std::cout << "default argument is at " << &f << std::endl; }The constructor for foo outputs its address; I got the following output from a single run: constructed foo @ 0x7ffff10bdb7f default argument is at 0x7ffff10bdb60
It shows that only 1 foo was constructed, and not at the same address as that of the default argument. It's been a loooong week, but I can't see anything wrong with the code. In the real code on which this was based, a segfault was occurring when running the destructor of a foo that was move-constructed from the default argument, because the underlying memory was seemingly uninitialised.
我们可以从 live example 看到4.9.0 没有说明这个问题。
我们可以从 defect report 994 看出这是有意的功能。和随后的决议N3217 :
This paper presents detailed wording changes relative to the current C++ Working Draft N3126 to implement brace-initializers for default arguments for functions, as proposed in N3139 "An Incomplete Language Feature" by Bjarne Stroustrup, thereby also addressing core issue 994.
提案N3139: An Incomplete Language Feature 中也涵盖了这一点。 .
有趣的是 Visual Studio also has a bug with respect to brace-initializers as default arguments我认为仍然没有解决。
关于c++ - GCC 中默认参数段错误的 std::map 参数和空括号初始化器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28837142/
在我的gem中,我需要yaml并且在我的本地计算机上运行良好。但是在将我的gem推送到rubygems.org之后,当我尝试使用我的gem时,我收到一条错误消息=>"uninitializedconstantPsych::Syck(NameError)"谁能帮我解决这个问题?附言RubyVersion=>ruby1.9.2,GemVersion=>1.6.2,Bundlerversion=>1.0.15 最佳答案 经过几个小时的研究,我发现=>“YAML使用未维护的Syck库,而Psych使用现代的LibYAML”因此,为了解决
exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby中使用两个参数异步运行exe吗?我已经尝试过ruby命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何rubygems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
这是在Ruby中设置默认值的常用方法:classQuietByDefaultdefinitialize(opts={})@verbose=opts[:verbose]endend这是一个容易落入的陷阱:classVerboseNoMatterWhatdefinitialize(opts={})@verbose=opts[:verbose]||trueendend正确的做法是:classVerboseByDefaultdefinitialize(opts={})@verbose=opts.include?(:verbose)?opts[:verbose]:trueendend编写Verb
我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere
我正在尝试在我的centos服务器上安装therubyracer,但遇到了麻烦。$geminstalltherubyracerBuildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingtherubyracer:ERROR:Failedtobuildgemnativeextension./usr/local/rvm/rubies/ruby-1.9.3-p125/bin/rubyextconf.rbcheckingformain()in-lpthread...yescheckingforv8.h...no***e
我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"
我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)
我在Rails工作并有以下类(class):classPlayer当我运行时bundleexecrailsconsole然后尝试:a=Player.new("me",5.0,"UCLA")我回来了:=>#我不知道为什么Player对象不会在这里初始化。关于可能导致此问题的操作/解释的任何建议?谢谢,马里奥格 最佳答案 havenoideawhythePlayerobjectwouldn'tbeinitializedhere它没有初始化很简单,因为你还没有初始化它!您已经覆盖了ActiveRecord::Base初始化方法,但您没有调
我想设置一个默认日期,例如实际日期,我该如何设置?还有如何在组合框中设置默认值顺便问一下,date_field_tag和date_field之间有什么区别? 最佳答案 试试这个:将默认日期作为第二个参数传递。youcorrectlysetthedefaultvalueofcomboboxasshowninyourquestion. 关于ruby-on-rails-date_field_tag,如何设置默认日期?[rails上的ruby],我们在StackOverflow上找到一个类似的问