C++ 将RAII与字符指针一起使用
我看到很多RAII示例类围绕着文件句柄 我试图在没有运气的情况下将这些示例改编为字符指针 我正在使用的库具有获取字符指针地址的函数(声明为get\u me\u A\u string(char**x))。 这些函数为该字符指针分配内存,并将其留给库的最终用户在自己的代码中进行清理 所以,我有这样的代码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
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());
}