释放包含malloc< d字符串的malloc结构

时间:2014-10-17 18:53:13

标签: c++ c pointers memory-management struct

我正在研究一个C ++库的包装器,我需要使用它来使用普通的C.这个库有一个名为checkError()的函数。此函数抛出与对象内发生的错误相关的异常。在C ++包装器中,我正在捕获此错误,mallocing一个C兼容的结构,将错误消息和信息分配给错误结构变量,然后我将指针传递回结构。这一切都很好,花花公子,但是一旦C调用函数处理完结构,我就担心内存泄漏。

对于这个问题,我们假设库的对象名为objectA,库名为libraryA这基本上就是我所拥有的:

C& C ++兼容wrapper.h

#ifndef LIBRARY_WRAPPER_DEFINITION
#define LIBRARY_WRAPPER_DEFINITION

#ifdef __cplusplus
extern "C" {
#endif

typedef struct wrapper_error_message_struct{
    char *what;
    char *typeAsText;
    unsigned char severityLevel; /* 0-10; 0 = lowest severity. 10 = highest severity */
} wrapper_error_message_t;

typedef void *pLibObj_t;

/**
 * I've omitted the other prototypes, typedefs, etc.
 **/

/* checkError()'s wrapper prototype */
wrapper_error_message_t *wrapper_check_error(pLibObj_t ptrObjectToCheck);

#ifdef __cplusplus
}
#endif
#endif

wrapper_check_errorwrapper.cpp的C ++实现:

/* Imports and other functions preceding wrapper_check_error() */
wrapper_error_message_t *wrapper_check_error(pLibObj_t ptrObjectToCheck){
    /* for the sake of this question, I've omitted the validity checks on
     * ptrObjectToCheck. I've also omitted my malloc checks. */
    libraryA::objectA *convertedObj = (libraryA::objectA *)ptrObjectToCheck;
    size_t structSize = sizeof(wrapper_error_message_t);
    size_t charSize = sizeof(char); // just in case it's not 1 on this system.
    try{
        convertedObj->checkError();
        /* if the checkError() function did not throw an error, then we
           can simply return NULL indicating that no ERROR was thrown */
        return NULL;
    }catch(libraryA::SomeLibraryExceptionType_1 &err){
        wrapper_error_message_t *cErr = (wrapper_error_message_t *)malloc(structSize);

        cErr->severityLevel = 3;

        const char *errWhat = err.what();
        cErr->what = (char *)malloc((strlen(errWhat)+1) * charSize);
        strcpy(cErr->what, errWhat);

        const char errorType[] = "Library Exception Type Name 1";
        cErr->typeAsText = (char *)malloc((strlen(errorType)+1) * charSize);
        strcpy(cErr->typeAsText, errorType);
        return cErr;

    }catch(libraryA::SomeLibraryExceptionType_2 &err){
        /*  Roughly the same as SomeLibraryExceptionType_1's catch statement */

    }catch(libraryA::SomeLibraryExceptionType_3 &err){
        /*  Roughly the same as SomeLibraryExceptionType_1's catch statement */

    }catch(std::exception &err)
        wrapper_error_message_t *cErr = (wrapper_error_message_t *)malloc(structSize);
        cErr->severityLevel = 7;
        const char *errWhat = err.what();
        cErr->what = (char *)malloc((strlen(errWhat)+1) * charSize);
        strcpy(cErr->what, errWhat);

        const char errorType[] = "Unknown standard exception (std::exception)";
        cErr->typeAsText = (char *)malloc((strlen(errorType)+1) * charSize);
        strcpy(cErr->typeAsText, errorType);
        return cErr;

    }catch(...){
        wrapper_error_message_t *cErr = (wrapper_error_message_t *)malloc(structSize);
        cErr->severityLevel = 10;
        cErr->what = NULL;

        const char errorType[] = "Unknown. Could not be caught.";
        cErr->typeAsText = (char *)malloc((strlen(errorType)+1) * charSize);
        strcpy(cErr->typeAsText, errorType);
        return cErr;
    }
}

wrapper_check_error()中使用main.c的普通C函数:

/* imports, irrelevant functions, irrelevant variable definitions */
void someFunction(){
    pLibObj_t ourWrappedObj;

    /*
     * function code before error check.
     */

    wrapper_error_message_t *errorMsg = wrapper_check_error(ourWrappedObj);
    if(wrapper_error_message_t != NULL){
        /* there was an error.
         * the code within this if statement:
         *      - processes the error message
         *      - logs information about it (current time, type, severity and the what message)
         *      - makes logical decisions about how to handle it if possible.
         */
        free(errorMsg);
        errorMsg = NULL;

        /* In the line above, the function frees the malloc'd structure to remove it
         * from the heap.
         *
         *        This free statement is what I'm concerned about.
         *
         */
    }
    // etc.
}

free(errorMsg)还会释放char *whatchar *typeAsText,因为他们是正在释放的结构的成员吗?基于我已经完成的一些阅读,我目前认为whattypeAsText指向的值仍然存在于堆上,因为errorMsg仅包含指向这些值的指针而不是价值观本身。

如果*what*typeAsText仍然在堆上,我将编写一个函数来释放结构的成员,然后释放结构本身。但是,如果有必要,我只想这样做。

如果有人可以就此提供一些指导/见解,我们将不胜感激。

谢谢。


如果这个问题重复,我会提前道歉。如果是,请指出我在类似问题的方向,以便我可以在那里阅读答案。我搜索了SO以及其他网站,但我没有找到任何能回答我问题的内容。

我从项目中摘录了代码,缩短了代码,并重命名了变量/函数。除了一些错误检查,如果我在某种程度上没有注意到的代码中有明显的错误,请发表评论,以便我可以修改它。如果有任何不清楚的地方,请在评论中告诉我,我会尽力更新问题并澄清。

1 个答案:

答案 0 :(得分:3)

由于有三个malloc()调用用于构建您将所有权传递给的对象:

    wrapper_error_message_t *cErr = (wrapper_error_message_t *)malloc(structSize);

    cErr->severityLevel = 3;

    const char *errWhat = err.what();
    cErr->what = (char *)malloc((strlen(errWhat)+1) * charSize);
    strcpy(cErr->what, errWhat);

    const char errorType[] = "Library Exception Type Name 1";
    cErr->typeAsText = (char *)malloc((strlen(errorType)+1) * charSize);
    strcpy(cErr->typeAsText, errorType);
    return cErr;

需要对free()进行3次调用:

    free(errorMsg->typeAsText);
    free(errorMsg->what);
    free(errorMsg);

作为旁注,根据定义,sizeof(char)为1,所以没有必要为此做任何特别的事情。

正如另一方面所说,我建议使用strdup()而不是容易出错的杂乱,如:

    cErr->what = (char *)malloc((strlen(errWhat)+1) * charSize);
    strcpy(cErr->what, errWhat);