[英]Using RAII with a character pointer
我看到很多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 *嗎?
謝謝
標准庫中已有一些東西可用:它叫做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());
一個非常基本的實現(你應該使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,因為正確的初始化發生的時間晚於構造函數,但它將負責清理。
你可以嘗試這樣的事情:
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
與自定義刪除工作一樣嗎?
我認為auto_ptr是你想要的
如果auto_ptr語義不適合你,則提升shared_ptr
對本地數組使用plain std::string
或boost :: scoped_array ,對於共享字符串使用boost :: shared_array (后者允許您提供自定義刪除以調用free()
。)
謝謝大家的回答。
不幸的是,我不能在這個項目中使用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;
}
另一種解決方案是這樣的,這就是我在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,那么寫一個不共享或傳輸資源的非常簡單的智能指針並不是很難。
這是基本的東西。 您可以將刪除器仿函數指定為模板參數。 我不是特別喜歡轉換運算符,所以請改用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());
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.