2017-07-21 51 views
0

我想返回char *,但我不希望函數用戶刪除free()的內存。如何在沒有免費()或刪除的情況下返回char *?

我有以下幾點:

namespace name_space 
{ 
    char* function(unsigned int i); 
} 

char* name_space::function(unsigned int i) 
{ 
    char buffer[MESSAGE]; 
    strerror_s(buffer,errno); 

    switch(i_exception) 
    { 
     case MESSAGE_RETURN:   return "No free or delete needed"; 
     case ERRNO_ERROR:    return buffer; 
     default:      return "UNKNOWN"; 
    } 
} 

當我返回 「MESSAGE_RETURN」 字符串沒有免費的()或刪除是必要的。但是,我怎麼能不使用新的或malloc返回緩衝區?

+7

使用['標準:: string'] (http://en.cppreference.com/w/cpp/string/basic_string)的所有字符串? –

+3

返回一個指向棧上的東西的指針?我*聞*訪問衝突 – Nyashes

+0

這是不可能的,以避免用戶釋放內存。您可以通過返回釋放析構函數中的內存的C++對象來避免* explicitley *釋放內存。當對象超出範圍時,它將被刪除並且內存將被釋放。這個對象有一個名字:'std :: string'。 – harper

回答

5

前提:

您的功能name_space::function不應該return buffer

buffer是一個本地(自動)變量,當函數返回時它會被銷燬。如果呼叫者功能嘗試訪問該內存,則可能會收到seg-fault或UB。


答:

如果需要返回一個字符串,怎麼樣一個簡單std::string?動態內存將由該類自動處理。

例如:

#include <string> 

std::string name_space::function(unsigned int i) { 
    char buffer[MESSAGE]; 
    strerror_s(buffer, MESSAGE, errno); 

    switch (i_exception) { 
     case MESSAGE_RETURN:   return "No free or delete needed"; 
     case ERRNO_ERROR:    return std::string(buffer); 
     default:      return "UNKNOWN"; 
    } 
} 
+0

所以,如果我返回這個並使用'cout << name_space :: function(ERRNO_ERROR).c_str()<< endl;'沒有內存泄漏? –

+0

@vincentpoortvliet否。當函數被解析時,'std :: cout'後臨時字符串將被銷燬並且內存將被析構函數釋放 –

+0

不需要使用'c_str()'輸出字符串。 C++流接受'std :: string'作爲輸出,所以'cout << name_space :: function(ERRNO_ERROR)<< endl'可以正常工作。 – Peter

0

如果你想忽略自己的函數中的內存分配,你應該把緩衝區從客戶端:

char* function(char buffer[], size_t capacity, unsigned int i) { 

    ... 
    return buffer; 
} 

在這種情況下,用戶可以決定如何分配緩衝區:

char buffer[1024] = {}; 
function(buffer, sizeof buffer, 1); 

std::vector<char> v(1024); 
function(&v[0], v.size(), 1); 
+0

在這種情況下,返回它是沒有意義的:返回計數或錯誤代碼會更有意義。 – EJP

+0

同意,但它只是例如 – AnatolyS

2

既然你問的問題,你可能知道,有什麼不對您的功能,但只是要清楚,所有的讀者:本地緩存將在被銷燬函數的結尾,因此在函數之外訪問它具有未定義的行爲。其次,你的函數聲明返回char*,而字符串文字是不變的。這使得你的程序從C++ 11開始就不合格。

可行的一個簡單的改變是使用strerror來代替,或者使本地緩衝區變爲靜態。這顯然有缺點,連續調用函數將取代以前的調用內容。

更好的方法是將內存處理委託給RAII容器。 RAII容器將分配所需的內存,移動時傳遞內存,並在銷燬時釋放內存。傳統的C++字符串RAII容器是標準庫中的std::string。只需返回std::string即可。這種變化也使得strerror一個簡單的選擇:

std::string name_space::function(unsigned int i) 
{ 
    switch(i_exception) 
    { 
     case MESSAGE_RETURN:   return "No free or delete needed"; 
     case ERRNO_ERROR:    return strerror(errno); 
     default:      return "UNKNOWN"; 
    } 
} 

這種方法也是方便,因爲它避免了潛在的溢出,如果你的MESSAGE太小。如果沒有strerrorlen_s,則不應使用strerror_s


PS。 C++標準庫不會繼承C標準庫中的strerror_s函數,因此您不能依賴它在C++程序中可用。即使在C中,該函數也是可選附件的一部分,因此它可能無法在符合C11的標準庫中使用。

2

您可以使用strerror()而不是strerror_s()。由strerror()返回的字符串指向靜態數據,不需要刪除。另外,不要返回字符串文字,因爲function()返回char*,而不是const char*。將返回類型更改爲const char*,或聲明包含錯誤消息的靜態char[]變量。

第一種選擇:

const char* name_space::function(unsigned int i) 
{ 
    switch(i_exception) 
    { 
     case MESSAGE_RETURN: return "No free or delete needed"; 
     case ERRNO_ERROR: return strerror(errno); 
     default:    return "UNKNOWN"; 
    } 
} 

第二個選項:

char* name_space::function(unsigned int i) 
{ 
    static char msg_no_free[] = "No free or delete needed"; 
    static char msg_unknown[] = "UNKNOWN"; 
    switch(i_exception) 
    { 
     case MESSAGE_RETURN: return msg_no_free; 
     case ERRNO_ERROR: return strerror(errno); 
     default:    return msg_unknown; 
    } 
} 

但是,如果你必須使用std::string的選項,那麼你應該使用來代替:

std::string name_space::function(unsigned int i) 
{ 
    switch(i_exception) 
    { 
     case MESSAGE_RETURN: return "No free or delete needed"; 
     case ERRNO_ERROR: return strerror(errno); 
     default:    return "UNKNOWN"; 
    } 
} 

在任何情況下,永遠不會返回一個指向非靜態局部變量的指針,就像你現在所做的那樣。這會導致調用者在函數返回後獲取指向不再存在的數據的指針。

0

如果你想控制比賽場上,但不希望的std::string的開銷,只要有適當的接口創建自己的string_view風格類:

#include <iostream> 
#include <string> 

namespace name_space 
{ 
    // control the playing field - make a proxy class 
    struct string_view 
    { 
     constexpr string_view(const char* p) 
     : p_(p) 
     {} 

     std::string to_string() const { return std::string(p_); } 
     std::ostream& write(std::ostream& os) const { 
      return os << p_; 
     } 
    private: 
     const char* p_; 
    }; 

    // give the proxy any required interface 
    auto to_string(const string_view& sv) { return sv.to_string(); } 
    auto operator<<(std::ostream& os, const string_view& sv) -> std::ostream& 
    { 
     return sv.write(os); 
    } 


    string_view function(unsigned int i); 
} 

name_space::string_view name_space::function(unsigned int i) 
{ 
    extern void strerror_s(char*, int); 
    constexpr auto MESSAGE = 1024;  
    static char buffer[MESSAGE]; 
    strerror_s(buffer,errno); 

    switch(i) 
    { 
     case 1:   return "No free or delete needed"; 
     case 2:    return buffer; 
     default:      return "UNKNOWN"; 
    } 
} 
+0

你的'name_space :: function'使用本地緩衝區構造字符串視圖。字符串視圖似乎只是將指針複製到成員。 'name_space :: function'返回後,該本地緩衝區仍然可用? – user2079303

+1

TBH我不明白你的'string_view'與返回一個簡單的'const char *'有什麼不同。它也持有一個指向本地數組(緩衝區)的指針,當函數返回時它將失效。 – Galik

+0

@加利克提出的問題是如何防止刪除指針,而不是整個企業是否是一個好主意。 –

相關問題