GCC-Visual Studio std::thread 编译器差异
Posted
技术标签:
【中文标题】GCC-Visual Studio std::thread 编译器差异【英文标题】:GCC-Visual Studio std::thread compiler differences 【发布时间】:2015-08-15 17:29:05 【问题描述】:编辑:最后添加了编译器错误。 首先,我要说我已经设置并运行了 Visual Studio Express 2013 和 CodeBlocks (Mingw w64)。 但是我在使用一个编译器而不是另一个编译器编译某些代码时遇到问题,反之亦然。
考虑这段代码:
void foo(std::string& s)
std::cout << "in foo function now" << std::endl;
s = "the new string.";
int main()
std::string s = "the original string";
std::thread t1(foo, std::ref(s));
t1.join();
if (!s.size()) std::cout << "s is empty" << std::endl;
else std::cout << s << std::endl;
std::cin.get();
return 0;
它在 GCC 和 VS 上都能正常编译和运行。
但是,如果我决定将 std::ref(s)
更改为 std::move(s)
,它将不再使用 GCC 编译,但可以使用 VS。
要修复它,我必须添加一个 '&' 使 void foo(std::string& s)
变为 void foo(std::string&& s)
,然后它将使用 gcc 编译,但不再使用 VS!
我的猜测是 VS 编译器是安静宽容的,并且没有严格遵守标准,但我没有使用 std::function 和 std::bind 的这种行为,即使参数传递相同我相信的方式。
无论如何,我非常感谢能帮助我了解正在发生的事情。
编辑:错误: 海湾合作委员会:
C:/mingw-w64/x86_64-5.1.0-posix-seh-rt_v4-rev0/mingw64/x86_64-w64-mingw32/include/c++/functional:1505:61: error: no type named 'type' in 'class std::result_of<void (*(std::__cxx11::basic_string<char>))(std::__cxx11::basic_string<char>&)>'
typedef typename result_of<_Callable(_Args...)>::type result_type;
^
C:/mingw-w64/x86_64-5.1.0-posix-seh-rt_v4-rev0/mingw64/x86_64-w64-mingw32/include/c++/functional:1526:9: error: no type named 'type' in 'class std::result_of<void (*(std::__cxx11::basic_string<char>))(std::__cxx11::basic_string<char>&)>'
_M_invoke(_Index_tuple<_Indices...>)
VS 一:
Error 1 error C2664: 'void (std::string &&)' : cannot convert argument 1 from 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>' to 'std::string &&' c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional 1149 1 Tests
【问题讨论】:
明确引用编译器错误。可能相关:std::thread constructor doesn't handle movable object Can't invoke or assign a std::function that has an rvalue reference as an argument (Visual C++)的可能重复foo(std::move(s))
也不应该编译。可变引用不会绑定到右值表达式。所以 std::move
将参数放入 std::thread
构造函数中预计不会起作用。
【参考方案1】:
MSVC 是错误的,无论是在标准下还是在实践中。
在内部,它们都将参数复制到类似tuple
的东西中,在生成的线程中解压它们并进行调用。
在标准下,调用表达式必须在复制它们后将值作为右值传递给被调用函数(当然,std::ref
情况除外)。
这是因为本标准中INVOKE
条款的措辞。之前在这里讨论过,但还没找到。
从逻辑上讲,tuple
中的值永远不会被再次使用,因此它应该在右值上下文而不是左值上下文中。按值取值,复制它,然后通过引用传递它,然后丢弃副本,这通常是一个错误。
【讨论】:
问题是function<void()> f1 = bind(f, move(s));
和 void f(string& s)
定义在 GCC 下工作和编译得很好,即使它的语法与 std::thread.
相同,这让我很困惑。
@ark 线程是一次调用,bind
是(可能)多次调用。字符串的值在 call-once 下被丢弃。而bind
和thread在标准中有不同的含义。我不流利使用bind
,因为我发现它目前已经过时了。以上是关于GCC-Visual Studio std::thread 编译器差异的主要内容,如果未能解决你的问题,请参考以下文章