【问题标题】:Why does creating a std::runtime_error reset WSAGetLastError?为什么创建 std::runtime_error 会重置 WSAGetLastError?
【发布时间】:2016-03-07 19:28:57
【问题描述】:

我正在从 Visual Studio 2013 更新到 Visual Studio 2015,并注意到这种行为差异。

#include <stdexcept>
#include <WinSock2.h>
#include <ws2tcpip.h>

int main()
{
    WORD version = MAKEWORD(2, 2);
    WSADATA wsaData;

    if (WSAStartup(version, &wsaData) != 0)
    {
        throw std::runtime_error("This one is not thrown");
    }

    WSASetLastError(1);

    if (WSAGetLastError() != 1)
    {
        throw std::runtime_error("This one neither");
    }

#if 1
    std::runtime_error test("an error");
#endif

    if (WSAGetLastError() != 1)
    {
        throw std::runtime_error("This is thrown when the above code path is enabled");
    }

    return 0;
}

当我启用 std::runtime_error 代码路径时,WSAGetLastError 标志被重置。禁用它,程序返回 0 没有任何问题。

【问题讨论】:

  • 你在哪里给WSAStartup打电话?阅读文档:msdn.microsoft.com/en-us/library/windows/desktop/…
  • 我删除了所有对于重现问题不是必需的代码,以使源代码对堆栈溢出更加友好。我最初有 WSAStartup 并且行为是相同的。
  • 修复它以避免将焦点从实际问题上移开

标签: c++ visual-studio exception visual-studio-2015 winsock2


【解决方案1】:

documentation 说:

如果函数调用的返回值表明错误代码中返回了错误或其他相关数据,则应立即调用 WSAGetLastError。这是必要的,因为如果某些函数成功,可能会将最后一个扩展错误代码重置为 0,从而覆盖先前失败的函数返回的扩展错误代码。

显然创建此错误对象会导致调用重置线程错误代码的函数。

碰巧WSAGetLastError is an alias for GetLastError,所以当你创建一个对象时,Win32 线程错误状态被修改也就不足为奇了。

【讨论】:

  • 我实际上看到了那段,但我认为只有其他 WSA 方法会重置标志。简单地构造一个异常会修改全局错误标志有点奇怪,因为它在 VS 版本之间发生了变化,我想知道它是否是一个错误。但我猜它与段落中的行为相匹配。谢谢。
  • 如何假设知道 std::runtime_error() 在做什么或不做什么?它可能会将自己记录到某个文件中,因此调用 WriteFile()。你为什么要假设这样的事情?
  • @Excess 发给谁?
【解决方案2】:

我在升级到 msvc2015 时遇到了类似的情况......一系列 N 显然不间断地调用 WSAGetLastError,最后一个返回的值与第一个 N-1 不同。它需要逐步通过汇编代码找到一个调用“new”的构造函数,这有时可能最终需要更多内存,这会重置系统错误代码。教训:如果您以后需要,缓存来自 WSAGetLastError 的值。

【讨论】:

    猜你喜欢
    • 2018-07-22
    • 2010-12-06
    • 2019-01-19
    • 1970-01-01
    • 2011-04-16
    • 1970-01-01
    • 1970-01-01
    • 2019-08-25
    相关资源
    最近更新 更多