C++ 将RAII与字符指针一起使用

C++ 将RAII与字符指针一起使用,c++,memory-management,raii,resource-management,C++,Memory Management,Raii,Resource Management,我看到很多RAII示例类围绕着文件句柄 我试图在没有运气的情况下将这些示例改编为字符指针 我正在使用的库具有获取字符指针地址的函数(声明为get\u me\u A\u string(char**x))。 这些函数为该字符指针分配内存,并将其留给库的最终用户在自己的代码中进行清理 所以,我有这样的代码 char* a = NULL; char* b = NULL; char* c = NULL; get_me_a_string(&a); if(a == NULL){ return

我看到很多RAII示例类围绕着文件句柄

我试图在没有运气的情况下将这些示例改编为字符指针

我正在使用的库具有获取字符指针地址的函数(声明为get\u me\u A\u 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++类来包装一个字符而不是文件*/p>
感谢一个非常基本的实现(您应该使其不可复制等)


从技术上讲,这不是RAII,因为正确的初始化发生在构造函数之后,但它将负责清理。

标准库中已经有一些可用的东西:它被称为

编辑:根据新信息:

它将分配内存并填充它 向上的我可以把内容复制到一个文件夹中 新的std::string对象,但我仍然 必须释放以前的记忆 由函数分配

对于实现者来说,这是一个糟糕的设计——分配的模块应该负责解除分配

好吧,现在我已经把它从我的系统里弄出来了:你可以用一个

template<typename T>
struct free_functor
{
    void operator() (T* ptr)
    {
        free(ptr);
        ptr=NULL;            
    }
};
shared_ptr<X> px(&x, free_functor());
模板
无结构函数
{
void运算符()(T*ptr)
{
免费(ptr);
ptr=NULL;
}
};
共享的_ptrpx(&x,free _函子());

我认为自动ptr是您想要的


或者增强共享\u ptr如果自动\u ptr语义对您不起作用

可以使用普通的
std::string,也可以使用本地数组或共享字符串(后者允许您提供自定义删除器来调用
free()

您可以尝试以下方法:

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);
}
模板
类自动删除数组
{
公众:
显式自动删除数组(常量T*ptr)
:ptr_(ptr)
{}
~AutoDeleteArray()
{
删除[]ptr;
//如果需要,使用免费的
//免费(ptr);
}
私人:
T*ptr;
};
//然后你可以像这样使用它:
{
char*a=NULL;
获取一个字符串(&a);
如果(a==NULL)
返回;
自动删除数组自动删除a(a);
}
这不是最可靠的解决方案,但可能足以达到目的


PS:我想知道,定制删除程序是否也可以使用
std::tr1::shared_ptr

谢谢大家的回答

不幸的是,我无法在此项目中使用boost或其他库。。。所以所有这些建议对我来说都是无用的

我已经研究过C语言中的异常处理,比如这里。。。

<> p>然后我研究了为什么C++没有一个最终的java,并且遇到了这个RAI.

我仍然不确定我是否会去析构函数的方法,只做代码C++,还是坚持C异常宏(使用可怕的Goto:)/P> Tronic提出了如下建议。 对于RAII或一般的析构函数,它们应该是无故障的吗?我猜不是

我唯一不喜欢的是,我现在不得不在printf语句中使用cast(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;
}
#包括
#包括
#包括
结构字符包装器{
char*str;
CharWrapper():str(){}//初始化NULL
~CharWrapper(){
printf(“%d自动释放\n”,str);
自由基(str);
}
//可用于C函数的转换
运算符char*(){return str;}
运算符char**(){return&str;}
};
//依赖于
//在调用者上释放内存
int get_a_str(字符**x){
*x=(char*)malloc(80*sizeof(char));
strcpy(*x,“你好!”;
printf(“%d已分配\n”,*x);
返回0;
}
int main(int argc,char*argv[]){
CharWrapper cw;
获得连续波;
如果(argc>1&&strcmp(argv[1],“segfault”)==0){
//让我们来说说吧
int*bad_ptr=NULL;
坏_ptr[8675309]=8675309;
}
printf(“字符串为:'%s'\n',(char*)cw);
返回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);

既然您说您不能使用boost,那么编写一个不共享或传输资源的非常简单的智能指针就不难了

这里有一些基本的东西。可以将deleter函子指定为模板参数。我并不特别喜欢转换运算符,所以请使用get()方法

随意添加其他方法,如release()和reset()

#包括
#包括
#包括
无结构
{
void运算符()(char*p)常量{free(p);}
};
模板
类唯一指针
{
T*ptr;
UniquePointer(const UniquePointer&);
UniquePointer&运算符=(const UniquePointer&);
公众:
显式唯一指针(T*p=0):ptr(p){}
~UniquePointer(){Deleter()(ptr);}
T*get()常量{return ptr;}
T**address(){return&ptr;}//给出这个是有风险的,但是哦。。。
};
无效愚蠢的乐趣(字符**s)
{
*s=静态(标准::malloc(100));
}
int main()
{
唯一指针我的_字符串;
愚蠢的乐趣(我的字符串.address());
std::strcpy(my_string.get(),“Hello world”);
std::put(my_string.get());
}

auto\u ptr删除内容,但他需要免费()。啊,是的-你可以向客户提供deleter-tho,但我会投票支持你的答案。auto\u ptr也不能很好地处理数组。我认为他使用的库返回需要释放的C字符串。我认为
auto\u ptr
不起作用,因为它必须是
免费的()
而不是
删除
。不过,我相信
boost::scoped_ptr
将允许您指定自定义删除器。实际上,我猜
scoped_ptr
不允许自定义删除器<代码>共享ptr
确实如此。我从未建议过
自动ptr
——如果我的帖子有这种感觉,我宁愿编辑它。是的,
s
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);
#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());
}