c++偶现问题备录(QString.toStdString().c_str())

C++偶现问题备录

1. 偶现问题源码

源码示例如下:

class KZNCalculationException : public std::exception
{
public:
#ifdef KZN_LINUX
KZNCalculationException(GString AMsg, GString AHit)
: std::exception()
{
m_sMsg = AMsg;
m_sHit = AHit;
}
#else
KZNCalculationException(GString AMsg, GString AHit)
: std::exception(AMsg.toStdString().c_str())
{
m_sHit = AHit;
}
#endif
GString getHit()
{
return m_sHit;
}
#ifdef KZN_LINUX
virtual const char* what() const throw ()
{
return m_sMsg.toStdString().c_str();
}
#endif
private:
GString m_sHit;
#ifdef KZN_LINUX
GString m_sMsg;
#endif
};

2. 问题根因分析

问题核心代码:m_sMsg.toStdString().c_str();

在Qt框架中,QString 是用于存储和操作Unicode字符串的类。当你需要将 QString 转换为标准C++字符串(即 std::string),以便与某些只接受C风格字符串(const char*)的API或函数交互时,你可能会遇到 QString.toStdString().c_str() 这样的表达式。下面我将详细解释这个表达式的含义和用法。

QString.toStdString()
QString.toStdString() 是 QString 类的一个成员函数,它返回一个 std::string 对象,该对象包含了与 QString 相同的字符序列,但编码为UTF-8(或系统默认的本地编码,这取决于Qt的配置和版本,但通常推荐和默认的是UTF-8)。这个转换是必需的,因为 QString 内部使用Unicode编码来存储字符串,而 std::string 通常用于存储以特定编码(如UTF-8)表示的字节序列。

std::string.c_str()
std::string.c_str() 是 std::string 类的一个成员函数,它返回一个指向以null结尾的字符数组(const char*)的指针,该数组包含了字符串的副本。这个指针指向的字符串是临时的,并且仅在调用 c_str() 的 std::string 对象存在期间有效。一旦 std::string 对象被销毁或修改,这个指针就可能指向无效的内存。

代码QString.toStdString().c_str() 的行为可能产生意外的结果,‌尤其是在处理临时字符串时。‌

在使用 QString::toStdString().c_str() 时,‌需要注意几个关键点:‌

  1. 临时字符串的问题:‌toStdString() 返回的是一个临时 std::string 对象。‌这个临时对象在调用 c_str() 时存在,‌但一旦 toStdString() 返回的 std::string 对象离开其作用域或被销毁,‌该临时对象也随之消失。‌因此,‌如果 c_str() 是在这个临时对象被销毁后调用的,‌返回的指针将指向一个无效的内存位置,‌这可能导致未定义的行为或程序崩溃。‌
  2. 避免的方法:‌为了避免上述问题,‌最佳实践是先将 QString 转换为 std::string,‌然后再调用该 std::string 的 c_str() 方法。‌这样做可以确保在调用 c_str() 时,‌std::string 对象仍然存在且有效。‌
  3. 特定环境的问题:‌在某些特定环境下,‌如 Windows 7 上使用 QString::toStdString() 可能会出现问题,‌尤其是在进行设备连接等操作时。‌这可能是因为操作系统或环境配置的不同导致的。‌

综上所述,‌虽然 QString::toStdString().c_str() 在某些情况下可能工作正常,‌但存在潜在的风险。‌开发者应当谨慎使用,‌并考虑上述提到的最佳实践,‌以确保代码的健壮性和稳定性。‌

3. 修复问题源码

3.1 修复方式一(开辟空间自主存储)

class KZNCalculationException : public std::exception
{
public:
#ifdef KZN_LINUX
KZNCalculationException(GString AMsg, GString AHit)
: std::exception()
{
QByteArray ba = AMsg.toLocal8Bit();
m_sMsg = new char[ba.size() + 1];
strcpy(m_sMsg, ba.data());
m_sHit = AHit;
}
#else
KZNCalculationException(GString AMsg, GString AHit)
: std::exception(AMsg.toStdString().c_str())
{
m_sHit = AHit;
}
#endif
GString getHit()
{
return m_sHit;
}
#ifdef KZN_LINUX
virtual const char* what() const throw (){
return m_sMsg;
}
#endif
private:
GString m_sHit;
#ifdef KZN_LINUX
char * m_sMsg;
#endif
};

3.2 修复方式二(利用std::string缓存)

class KZNCalculationException : public std::exception
{
public:
#ifdef KZN_LINUX
KZNCalculationException(GString AMsg, GString AHit)
: std::exception()
{
m_sMsg = AMsg.toStdString();
m_sHit = AHit;
}
#else
KZNCalculationException(GString AMsg, GString AHit)
: std::exception(AMsg.toStdString().c_str())
{
m_sHit = AHit;
}
#endif
GString getHit()
{
return m_sHit;
}
#ifdef KZN_LINUX
virtual const char* what() const throw (){
return m_sMsg.c_str();
}
#endif
private:
GString m_sHit;
#ifdef KZN_LINUX
std::string m_sMsg;
#endif
};
posted @   kaizenly  阅读(89)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
历史上的今天:
2017-08-29 常对象与this指针
2013-08-29 [3] 智能指针std::auto_ptr
打赏

喜欢请打赏

扫描二维码打赏

微信打赏

点击右上角即可分享
微信分享提示