作为介绍,请注意,我是一名 Java 程序员,仍在习惯 C++ 中的内存管理问题。
我们有一个基类,用于将对象编码为 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;
}
更新
嗯 - 我应该更准确地了解 encode()
的结果是如何使用的。它被传递给 boost:async_write,并且程序崩溃,因为我相信字符串在 async_write 完成之前超出了范围。看来我需要将返回的字符串复制到一个类成员,该成员在发送消息的类的生命周期内一直处于事件状态(?)。
这是 encode()
方法的实际使用方式(在我将 的返回值更改为 string
之后):
void iserver_client::send(ezx::iserver::EZXMsg& msg) {
string encoded = msg.encode();
size_t bytes = encoded.length();
boost::asio::async_write(socket_, boost::asio::buffer(encoded, bytes), boost::bind(&iserver_client::handle_write, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
看起来正确的方法是维护一个异步写入的字符串队列/列表/vector 。如前所述here (也在 boost chat_client 示例中)。 (但这是一个单独的问题。)
最佳答案
对于这个问题: 在你的复制函数中,你返回一个指向堆内存的指针!所以用户可能会造成内存泄漏,我认为你不能使用这个复制函数,你可以在你的编码函数中这样做:
return data.str();
如果想得到一个char*,可以使用string的成员函数:c_str(), 就像这样:
string ss("hello world");
const char *p = ss.c_str();
如果您使用堆栈字符串对象,则不会造成内存泄漏,
关于c++ - 如何使这段代码不易发生内存泄漏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17636088/