2014-10-17 29 views
1

我正在处理一个C++库的包装,我需要使用plain C.该库具有一个名为checkError()的函数。该函数会引发与对象内发生的错误相关的异常。在C++包装器中,我捕获了这个错误,mallocing一个C兼容的结构,将错误消息和信息分配给错误结构变量,然后我将指针传递回结构。这一切都很好,但是我一直担心C调用函数处理完结构后会发生内存泄漏。释放包含malloc'd字符串的malloc'd结构

对于这个问题,我们假设该库的对象称为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 

C++实现的wrapper_check_errorwrapper.cpp

/* 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; 
    } 
} 

这是在main.c使用wrapper_check_error()的普通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仍然在堆上,我会写一个函数来释放结构成员,然后释放结构本身。但是,如果有必要,我只想这样做。

如果有人可以提供一些关于此的指导/见解,将不胜感激。

谢谢。


如果这个问题是重复的,我很抱歉。如果是这样,请将问题指向类似问题的方向,以便我可以阅读那里的答案。我搜索了以及其他网站,但我还没有找到任何答案我的问题。

我从我的项目中摘录了代码,缩短了代码,并重命名了变量/函数。除了一些错误检查之外,如果代码中存在明显的错误,我不知何故,请发表评论,以便我可以修改它。如果有什么不清楚的地方,请在评论中告诉我,我会尽我所能来更新问题并进行澄清。

+3

'free'不是递归(这是不可能的,它无法知道的方式你有其他的指向内部块,并希望保持它们)。您必须手动释放成员指针指向的块。 – 2014-10-17 18:57:10

+0

谢谢,很高兴知道。我知道'free'接收一个'void *'作为参数,所以这让我更加不确定是否释放了整个结构。也就是说,如果C++包装器是用托管C++实现而不是本地编写的,情况会不会改变?例如,如果包装器是用MSVC而不是本地C++编写的,那么释放结构本身就成为一种有效的方法来删除其中的C字符串?我只问,因为MSVC有一个内置的垃圾收集器。我计划使用本机C++来保持项目,所以我只是将MSVC作为一个学术问题。 – SpencerD 2014-10-17 19:05:53

回答

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; 

有将需要3调用free()

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

作为一个边注意,sizeof(char)是1的定义,所以没有必要为此做任何特殊的事情。

而作为另一个方面说明,我建议使用strdup()代替容易出错的混乱,如:

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

非常感谢您澄清这一点。另外,我从来没有听说过'strdup',但那比我所做的要好得多。我读过一些使用'sizeof(char)'的代码,所以我一直在使用它,因为作者声明char可以大于1。也许他的意思是一些较旧的系统可能有超过8位的字符。无论如何,我在问题的评论中问过,但如果这个项目是用托管的C++实现(如MSVC)编写的,那么内置的垃圾收集器会照顾成员吗?我坚持本地C++,但我只是好奇。 – SpencerD 2014-10-17 19:18:59

+1

我对C++/CLI(或今天调用的任何托管C++)并不是很熟悉,但我的期望是使用'malloc()'分配的任何东西都不会被托管垃圾收集器处理。如果使用'gcnew'分配,那么托管垃圾收集器应该处理它。 – 2014-10-17 19:24:36