【发布时间】:2018-11-07 23:50:02
【问题描述】:
我不熟悉 C,但我必须为我的 C++ 软件编写一个 C 接口才能将其作为动态库提供。关于经典实践,我有两个问题:
- 传递和接收字符串的经典方法是什么?谁负责记忆?
- 始终保留错误代码的返回值,然后在参数中接收带有指针的值是个好主意吗?如果不是,为什么?
这是一个示例,用我最初想象的代码说明我的问题:
int define_new_population(int* id)
{
// all_pop is a std::map<int,std::vector<boost::shared_ptr<Element>>>
*id = generate_id();
all_pop[*id] = std::vector<boost::shared_ptr<Element>>();
return 0;
}
int add_element_type1_in_pop(int pop_id, const char* name, double lower_bound, double upper_bound)
{
if(all_pop.find(pop_id) == all_pop.end())
return ERROR_CODE_WRONG_ID;
const std::string str_name(name);
try { all_pop[pop_id].push_back(boost::shared_ptr<Element>(new ElementType1(str_name, lower_bound, upper_bound))); }
catch(...) { return ERROR_CODE_FOO; }
return 0;
}
int add_element_type2_in_pop(int pop_id, const char* name, double reference)
{
if(all_pop.find(pop_id) == all_pop.end())
return ERROR_CODE_WRONG_ID;
const std::string str_name(name);
try { all_pop[pop_id].push_back(boost::shared_ptr<Element>(new ElementType2(str_name, reference))); }
catch(...) { return ERROR_CODE_BAR; }
return 0;
}
int get_population_size(int pop_id, int* pop_size)
{
if(all_pop.find(pop_id) == all_pop.end())
return ERROR_CODE_WRONG_ID;
*pop_size = (int)all_pop[pop_id].size();
return 0;
}
int get_element_name(int pop_id, int elem_index, char** name)
{
if(all_pop.find(pop_id) == all_pop.end())
return ERROR_CODE_WRONG_ID;
if(elem_index >= (int)all_pop[pop_id].size())
return ERROR_CODE_OUT_OF_RANGE;
const std::string& str_name = all_pop[pop_id][elem_index].getName();
*name = malloc(sizeof(char) * (str_name.length() + 1));
strcpy(*name, str_name.c_str());
return 0;
}
【问题讨论】:
-
*name = malloc(sizeof(char) * (str_name.length() + 1));您的动态库分配了内存,由您的库来释放它。您将需要提供一个函数来执行此操作。应用程序和共享库不一定共享相同的运行时支持和堆。所以他们不能分配和释放彼此的内存。 -
补充(讨论):大约一半的 MS-Windows API 要求调用者预先分配一个缓冲区并将指针和大小传递给 API(可以返回缓冲区不够大的错误和所需的大小)。在这种情况下,调用者负责释放内存。其他时候,MS-Windows API 为 API 调用分配缓冲区,并为调用者提供一个空闲内存调用,以便在内存使用完毕时使用。
-
我认为调用者应该负责内存管理。
-
正如 Richard Critten 所说,您的动态库分配了内存,由您的库来释放它。但大多数时候这是不可能的。你应该做的是提供一个函数来释放内存并记录应用程序必须调用这个函数来释放内存。
-
像
define_new_population这样总是返回 0 的函数通常没有意义。它不会失败,所以不要返回错误代码。 -- 在这种情况下,尽管您未能捕获 std::bad_alloc 并返回适当的错误代码。