Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/65.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 清理代码的正确方法是什么?_C++_C_Windows - Fatal编程技术网

C++ 清理代码的正确方法是什么?

C++ 清理代码的正确方法是什么?,c++,c,windows,C++,C,Windows,当您有几行代码启动其他对象时,是否有比下面所示更干净的方法来清理对象?我在一个函数中启动了几个对象,并检查它们是否失败——但我有一堆多余的代码,我必须继续键入。下面显示的方法是否正确?还是有更干净的方法?我知道do{}while(false)方法和goto方法,但它们并不干净,而且感觉很凌乱 if( bind(s, (sockaddr *)&saddr, sizeof(sockaddr)) == SOCKET_ERROR ) { printf("bind() fa

当您有几行代码启动其他对象时,是否有比下面所示更干净的方法来清理对象?我在一个函数中启动了几个对象,并检查它们是否失败——但我有一堆多余的代码,我必须继续键入。下面显示的方法是否正确?还是有更干净的方法?我知道do{}while(false)方法和goto方法,但它们并不干净,而且感觉很凌乱

    if( bind(s, (sockaddr *)&saddr, sizeof(sockaddr)) == SOCKET_ERROR ) {
        printf("bind() failed.\n");
        closesocket(s);
        CloseHandle(g_hIOCompletionPort);
        CloseHandle(g_hShutdownEvent);
        WSACleanup();
    }

    if( listen(s, 60) == SOCKET_ERROR ) {
        printf("listen() failed.\n");
        closesocket(s);
        CloseHandle(g_hIOCompletionPort);
        CloseHandle(g_hShutdownEvent);
        WSACleanup();
    }

    g_hAcceptEvent = WSACreateEvent();
    if( g_hAcceptEvent == WSA_INVALID_EVENT ) {
        printf("WSACreateEvent() failed.\n");
        closesocket(s);
        CloseHandle(g_hIOCompletionPort);
        CloseHandle(g_hShutdownEvent);
        WSACleanup();
    }
< C++ >是这种情况下非常常见的模式。

对于普通C:如果我写goto,我会被杀,所以我不会。但请看这里的例子:

如果你使用C++,那么首选方法。基本上,您可以获取资源或将其附加到类(通常在构建期间),并在销毁期间释放资源


例如,在您的代码中,您会遇到某种类型的<代码>句柄类,它保存在<代码> GyHioFuleTeNotoP> <代码>句柄中,并在其析构函数中调用<代码> CloseHandle <代码> .p> >通常,RAII将在C++中使用,其中代码是由具有构造函数和析构函数的对象组织的,清理是在析构函数中执行的。因此,销毁对象就足够了,这限制了复制代码的数量

class Server {
    SOCKET s;
    HANDLE iocp;
    HANDLE shutdown;
    std::string err_str;
public:
    ~Server () {
        if (!err_str.epmty()) std::cerr << err_str << '\n';
        closesocket(s);
        CloseHandle(iocp);
        CloseHandle(shutdown);
        WSACleanup();
    }
    //...
};
在C语言中,没有RAII等价物。也没有例外。但是,可以使用
setjmp()
longjmp()
来模拟异常处理,就像使用一样。尽管没有对RAII的直接支持,但没有任何东西可以阻止您将C代码组织到具有相关清理函数的对象中

struct Server {
    SOCKET s;
    HANDLE iocp;
    HANDLE shutdown;
    const char *err_str;
};

void destroy_server (Server *server) {
    /* ... */
}
如果有很多代码遵循一个序列,但其中任何一个都可能需要进行清理,那么可以像状态机一样组织代码

enum { STATE_INIT, STATE_SUCCESS, STATE_ERROR, STATE_STOP } state = STATE_INIT;

while (state != STATE_STOP) {
    switch (state) {
    case STATE_INIT:    state = do_server_init(); break;
    case STATE_SUCCESS: state = do_server(); break;
    case STATE_ERROR:   state = do_server_cleanup(); break;
    case STATE_STOP:    break;
    default:            fprintf(stderr, "unexpected state: %d\n", state);
                        state = STATE_ERROR;
    }
}

这是离题的;试试看。:)即使在
bind
失败且已完成清理的情况下,您似乎也在调用
listen
。这很奇怪。
enum { STATE_INIT, STATE_SUCCESS, STATE_ERROR, STATE_STOP } state = STATE_INIT;

while (state != STATE_STOP) {
    switch (state) {
    case STATE_INIT:    state = do_server_init(); break;
    case STATE_SUCCESS: state = do_server(); break;
    case STATE_ERROR:   state = do_server_cleanup(); break;
    case STATE_STOP:    break;
    default:            fprintf(stderr, "unexpected state: %d\n", state);
                        state = STATE_ERROR;
    }
}