деструктор / обратный вызов в C для получения поведения shared_ptr - PullRequest
0 голосов
/ 17 мая 2011

Я пишу слушатель сокета на C. Когда он это принимает, он создает новый поток (отсоединяется), получая данные и обрабатывая их.

Но каждый раз мне нужно вручную вызывать close (socket_descriptor).Если бы это был C ++, я мог бы каким-то образом решить закрыть его внутри деструктора.

Я пытался найти что-то, что обеспечивает мне такое же поведение.
По сути, я хочу создать что-то вроде shared_ptr в C.

Есть ли в C хоть какой-то способсигнал или уведомление, когда объект выходит из области видимости?

Ответы [ 3 ]

3 голосов
/ 17 мая 2011

Нет, это не присуще C ... чтобы включить что-то вроде того, о чем вы просите, вам потребуется создать какой-то механизм обратного вызова, который будет использовать справочную таблицу для сопоставления объекта с его «разрушитель» и вызывает эту общую функцию обратного вызова в конце каждой функции, которую вы пишете, или, более вероятно, в конце каждой области видимости, где был объявлен объект. Я бы посчитал это очень запутанным и сложным, и, в конце концов, это, вероятно, намного сложнее, чем стоит, т. Е. Вы могли бы просто использовать goto и написать весь свой код очистки в конце функции (я в общем, использование goto считается очень плохим стилем, но для перехода к коду очистки в конце функции они могут сделать код намного чище, чем альтернатива, которая состоит в том, чтобы повторять одно и то же очищение каждый раз при появлении ошибки).

Например, предположим, что у вас есть функция, которая выделяет некоторую память и открывает файловый дескриптор в какой-то ранний момент в функции, но затем, если были некоторые ошибки, невозможно продолжить ... вы не можете просто вернуть ошибку код, вы должны сделать некоторую очистку, но было бы больно повторять код очистки снова и снова прямо в середине кода:

int my_function()
{
    int* array_on_heap = malloc(ARRAYSIZE * sizeof(int));
    int file_descriptor;

    //...some code

    if (some_ptr == NULL)
        goto error_cleanup;

    //...some more code

    if (some_other_pointer != some_ptr)
        goto error_cleanup;

    //...even more code

    //normal return with no error
    return 0;

    error_cleanup:
        //clean-up code in case there was an error
        free(array_on_heap);
        close(fd);
        return -1;
}

Это осознанное и разумное использование goto здесь создает очень лаконичную область функции, в которой могут происходить разрушение и очистка, и вам не нужно беспокоиться о возможной потере функциональности очистки, если вы решили посыпать код очистки действительной «механикой» самой функции.

1 голос
/ 17 мая 2011

Не существует такого понятия, как автоматический деструктор в старом старом C. Вы рассматривали возможность сделать это через сборщик мусора ?

Например, вы можете использовать Boehm-Demers-Weiser консервативный сборщик мусора , чтобы выделить ваши объекты, а затем вызвать GC_REGISTER_FINALIZER, чтобы закрыть дескриптор сокета, когда объект становится недоступным.

Другое решение может заключаться в переносе объектафункция обратного вызова клиента в другую функцию, которая просто вызывает обратный вызов и затем закрывает сокет.Таким образом, вам не придется закрывать его явно в каждой функции обратного вызова.

0 голосов
/ 17 мая 2011

Есть только один способ сделать это в «сыром» C:

void abc_init (parameters);

void abc_cleanup (parameters);

где все функции abc принадлежат модулю abc, который состоит из abc.h и abc.c. Распределение объектов может быть затем обработано вызывающим модулем abc или самим модулем:

// alternative 1, leave allocation to the caller

#include "abc.h"

int main()
{
  Abc_t x;

  abc_init(&x);

  ...

  abc_cleanup(&x);
}


// alternative 2, the module handles allocation

// abc.c

static Abc_t* x;

void abc_init (parameters)
{
  x = some_sort_of_allocation();
  set x based on parameters
}


...

void abc_cleanup (parameters)
{
  cleanup x
}
...