我看到很多RAII示例类环绕文件句柄。
我试图将这些例子毫不费力地改编成字符指针。
我正在使用的库具有获取字符指针地址的函数(声明为get_me_a_string(char ** x))。 这些函数为该字符指针分配内存,并将其留给库的最终用户,以便在自己的代码中清理它。
所以,我的代码看起来像这样......
char* a = NULL;
char* b = NULL;
char* c = NULL;
get_me_a_string(&a);
if(a == NULL){
return;
}
get_me_a_beer(&b);
if(b == NULL){
if(a != NULL){
free(a);
}
return;
}
get_me_something(&c);
if(c == NULL){
if(a != NULL){
free(a);
}
if(b != NULL){
free(b);
}
return;
}
if(a != NULL){
free(a);
}
if(b != NULL){
free(b);
}
if(a != NULL){
free(b);
}
听起来RAII就是我上面这个烂摊子的答案。 有人可以提供一个简单的C ++类来包装char *而不是FILE *?
由于
答案 0 :(得分:5)
标准库中已有一些东西可用:它叫std::string
。
编辑:根据新信息:
它将分配内存并填充它 起来。我可以将内容复制到一个 新的std :: string对象,但我还是 必须释放那些记忆 由函数分配。
这是实现者部分的糟糕设计 - 分配的模块应该负责解除分配。
好的,现在我已经从我的系统中解决了这个问题:你可以使用boost::shared_ptr
来解放。
template<typename T>
struct free_functor
{
void operator() (T* ptr)
{
free(ptr);
ptr=NULL;
}
};
shared_ptr<X> px(&x, free_functor());
答案 1 :(得分:2)
一个非常基本的实现(你应该使noncopyable等)。
struct CharWrapper {
char* str;
CharWrapper(): str() {} // Initialize NULL
~CharWrapper() { free(str); }
// Conversions to be usable with C functions
operator char**() { return &str; }
operator char*() { return str; }
};
这在技术上不是RAII,因为正确的初始化发生的时间晚于构造函数,但它会负责清理。
答案 2 :(得分:1)
您可以尝试这样的事情:
template <typename T>
class AutoDeleteArray
{
public:
explicit AutoDeleteArray(const T* ptr)
: ptr_(ptr)
{}
~AutoDeleteArray()
{
delete [] ptr_;
// if needed use free instead
// free(ptr_);
}
private:
T *ptr_;
};
// and then you can use it like:
{
char* a = NULL;
get_me_a_string(&a);
if(a == NULL)
return;
AutoDeleteArray<char> auto_delete_a(a);
}
这不是最可靠的解决方案,但可能足够用于此目的。
PS:我想知道自己的std::tr1::shared_ptr
自定义删除器工作吗?
答案 3 :(得分:0)
我认为auto_ptr就是你想要的
如果auto_ptr语义不适合你,或者提升shared_ptr
答案 4 :(得分:0)
对本地数组使用普通std::string
或boost::scoped_array,对共享字符串使用boost::shared_array(后者允许您提供自定义删除以调用free()
。)< / p>
答案 5 :(得分:0)
感谢大家的回答。
不幸的是,我不能在这个项目中使用boost或其他库...所以这些建议对我来说都是无用的。
我在这里看过像C这样的异常处理之类的东西...... http://www.halfbakery.com/idea/C_20exception_20handling_20macros
然后我看了为什么C ++没有最终像Java一样,并且遇到了这个RAII的东西。
我仍然不确定我是否会采用析构函数方式并仅使用C ++代码,或者坚持使用C异常宏(使用可怕的goto:)
Tronic建议如下。 对于RAII或一般的析构函数,它们应该是段错误证明吗?我猜不是。
我唯一不喜欢的是我现在必须在我的printf语句中使用强制转换(char *)。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct CharWrapper {
char* str;
CharWrapper(): str() {} // Initialize NULL
~CharWrapper() {
printf("%d auto-freed\n", str);
free(str);
}
// Conversions to be usable with C functions
operator char*() { return str; }
operator char**() { return &str; }
};
// a crappy library function that relies
// on the caller to free the memory
int get_a_str(char **x){
*x = (char*)malloc(80 * sizeof(char));
strcpy(*x, "Hello there!");
printf("%d allocated\n", *x);
return 0;
}
int main(int argc, char *argv[]){
CharWrapper cw;
get_a_str(cw);
if(argc > 1 && strcmp(argv[1], "segfault") == 0){
// lets segfault
int *bad_ptr = NULL;
bad_ptr[8675309] = 8675309;
}
printf("the string is : '%s'\n", (char*)cw);
return 0;
}
答案 6 :(得分:0)
另一种解决方案是这样的,这就是我在C中编写这段代码的方式:
char* a = NULL;
char* b = NULL;
char* c = NULL;
get_me_a_string(&a);
if (!a) {
goto cleanup;
}
get_me_a_beer(&b);
if (!b) {
goto cleanup;
}
get_me_something(&c);
if (!c) {
goto cleanup;
}
/* ... */
cleanup:
/* free-ing a NULL pointer will not cause any issues
* ( see C89-4.10.3.2 or C99-7.20.3.2)
* but you can include those checks here as well
* if you are so inclined */
free(a);
free(b);
free(c);
答案 7 :(得分:0)
既然你说你不能使用boost,那么编写一个不共享或传输资源的非常简单的智能指针并不是很难。
这是基本的东西。您可以将删除器仿函数指定为模板参数。我并不特别喜欢转换运算符,所以请改用get()方法。
随意添加其他方法,如release()和reset()。
#include <cstdio>
#include <cstring>
#include <cstdlib>
struct Free_er
{
void operator()(char* p) const { free(p); }
};
template <class T, class Deleter>
class UniquePointer
{
T* ptr;
UniquePointer(const UniquePointer&);
UniquePointer& operator=(const UniquePointer&);
public:
explicit UniquePointer(T* p = 0): ptr(p) {}
~UniquePointer() { Deleter()(ptr); }
T* get() const { return ptr; }
T** address() { return &ptr; } //it is risky to give out this, but oh well...
};
void stupid_fun(char** s)
{
*s = static_cast<char*>(std::malloc(100));
}
int main()
{
UniquePointer<char, Free_er> my_string;
stupid_fun(my_string.address());
std::strcpy(my_string.get(), "Hello world");
std::puts(my_string.get());
}