我正在尝试返回char *,但我不希望函数用户删除free()内存。
我有以下内容:
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" string不需要free()或delete。但是如何在不使用new或malloc的情况下返回缓冲区?
答案 0 :(得分: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";
}
}
答案 1 :(得分: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
太小,它可以避免潜在的溢出。如果没有strerror_s
,就不应该使用strerrorlen_s
。
PS。 C ++标准库不从C标准库继承strerror_s
函数,因此您不能依赖它在C ++程序中可用。即使在C语言中,该函数也是可选附件的一部分,因此它可能也不适用于符合C11标准的库。
答案 2 :(得分: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";
}
}
无论如何,永远不要像现在这样返回指向非静态局部变量的指针。这导致调用者获得指向函数返回后不再存在的数据的指针。
答案 3 :(得分: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);
答案 4 :(得分: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";
}
}