Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使此代码不易发生内存泄漏? 作为介绍,请注意,我是一个java程序员,仍然习惯C++中的内存管理问题。p>_C++_Memory Management - Fatal编程技术网

如何使此代码不易发生内存泄漏? 作为介绍,请注意,我是一个java程序员,仍然习惯C++中的内存管理问题。p>

如何使此代码不易发生内存泄漏? 作为介绍,请注意,我是一个java程序员,仍然习惯C++中的内存管理问题。p>,c++,memory-management,C++,Memory Management,我们有一个基类,用于将对象编码为ASCII字符字符串。本质上,该类使用stringstream类成员将不同的数据类型转换为一个长字符串,然后将char*返回给包含编码对象数据的调用者 在测试内存泄漏时,我发现我们使用的实现似乎容易产生内存泄漏,因为用户必须始终记住删除方法的返回值。以下是守则有关部分的摘录: char* Msg::encode() { // clear any data from the stringstream clear();

我们有一个基类,用于将对象编码为ASCII字符字符串。本质上,该类使用
stringstream
类成员将不同的数据类型转换为一个长字符串,然后将
char*
返回给包含编码对象数据的调用者

在测试内存泄漏时,我发现我们使用的实现似乎容易产生内存泄漏,因为用户必须始终记住删除方法的返回值。以下是守则有关部分的摘录:

    char* Msg::encode() 
    {
        // clear any data from the stringstream
        clear();
        if (!onEncode()) {
            return 0;
        }

        // need to convert stringstream to char*
        string encoded = data.str();
                    // need to copy the stringstream to a new char* because 
                    // stringstream.str() goes out of scope when method ends
        char* encoded_copy = copy(encoded);
        return encoded_copy;
    }

    bool Msg::onEncode(void)
    {
        encodeNameValue(TAG(MsgTags::TAG_USERID), companyName);
        encodeNameValue(TAG(MsgTags::TAG_DATE), date);
        return true;
    }

    bool EZXMsg::encodeNameValue(string& name, int value)
    {
        if(empty(value))
        {
            return true;
        }
                    // data is stringstream object
        data << name << TAG_VALUE_SEPARATOR << value << TAG_VALUE_PAIRS_DELIMITER;
        return true;
    }


    char* copy(string& source) {
        char *a=new char[source.length() +1];
        a[source.length()]=0;
        memcpy(a,source.c_str(),source.length());
        return a;
    }

这样做的正确方法似乎是维护要异步写入的字符串的队列/列表/向量。如前所述(以及boost chat_客户端示例)。(但这是一个单独的问题。)

您可以返回一个
std::string
。无论如何,您在那里有一个:

string Msg::encode() 
{
    // clear any data from the stringstream
    clear();
    if (!onEncode()) {
        return string{};
    }

    return data.str();
}
然后,调用方看起来像:

Msg msg;
msg.userID = 1234;
send(msg.encode().c_str());
关于这个问题: 在复制函数中,返回一个指向堆内存的指针!因此,用户可能会造成内存泄漏,我认为您不能使用此复制功能,您可以在“编码”功能中执行如下操作:

return data.str();
如果要获取char*,可以使用string:c_str()的成员函数, 就这样,

string ss("hello world");
const char *p = ss.c_str();
如果使用堆栈字符串对象,则不会产生内存泄漏,

实现“自动”删除的唯一方法是堆栈变量(在某些级别)超出范围。事实上,这通常是保证删除的唯一方法,例如,即使在出现异常的情况下也是如此

正如其他人提到的
std::string
工作正常,因为
char*
属于分配给
string
的堆栈,这将删除
char*

这通常不起作用,例如对于非
char*
类型

RAII(ResourceAcquisitionisInitialization)是一个有用的习惯用法,用于处理诸如内存管理、锁获取/释放等问题

一个好的解决方案是使用Boost,如下所示:

{
  Msg msg;
  msg.userID = 1234;
  scoped_array<char> encoded(msg.encode());
  send(encoded.get());
  // delete[] automatically called on char *
}
{
味精;
msg.userID=1234;
作用域数组编码(msg.encode());
send(encoded.get());
//在char上自动调用delete[]*
}
对非数组类型也适用


仅供参考:您应该使用
delete[]encoded
来匹配
new char[source.length()+1]

当使用
std::string
可以充分解决您的特定问题时,一般的解决方案是返回
std::unique\u ptr
而不是原始指针

std::unique_ptr<char[]> Msg::encode() {
    :
    return std::unique_ptr<char[]>(encoded_copy);
}

编码的
超出范围并被销毁时,内存将自动释放。

这取决于所需的API是什么。最大的问题是:返回的
char*
应该有效多长时间?谁应该释放与其相关的内存?为什么不从
encode()
方法返回
string
(或者传递对
string
的引用)?不要使用
char*
作为返回类型;事实上,避免使用原始的
char*
字符串,并使用
std::string
。使用RAII(资源获取是初始化)确保异常和正常使用避免泄漏。尽可能避免
new
;当你做不到的时候要非常小心。@SamGoldberg:我不确定你是否可以假设boost正在为你复制缓冲区。我更倾向于相信,在系统调用期间,唯一的拷贝是从用户空间复制到内核空间。因此,在收到发送已完成的异步通知之前,可能无法释放指针。@Sam:A
string
对象只是
char*
的包装器。返回时,返回的对象是临时对象,因此将使用move构造函数,这只是将内存提供给另一个
string
对象,而不是复制它。return
0
to string对象将使其崩溃。因为您正在用null初始化字符串pointer@chris:我知道。。。sighah-感谢您提供有关删除[]编码的提示。我不知道。使用unique_ptr和boost::shared_ptr有什么区别?@SamGoldberg:a
unique_ptr
无法复制,只能移动,因此它是指向对象的唯一指针。与
unique\u ptr
相比,
std::shared\u ptr
(与
boost::shared\u ptr
几乎相同)有一些开销(引用计数),不能很好地处理数组,而
unique\u ptr
有一个专门的数组版本。感谢您的解释。一切都开始变得更有意义了。
std::unique_ptr<char[]> Msg::encode() {
    :
    return std::unique_ptr<char[]>(encoded_copy);
}
auto encoded = msg.encode();
send(encoded.get());