如何在没有free()或delete的情况下返回char *?

时间:2017-07-21 08:07:34

标签: c++

我正在尝试返回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的情况下返回缓冲区?

5 个答案:

答案 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";
    }
}