C字符串函数的包装类有什么问题吗?

3

我有一些用C风格编写的C++代码。
由于某些原因,我不能使用C++的字符串和IO库,所以在处理字符串时,我应该只使用像sprintfitoa等函数。

我想要用以下代码替换需要临时缓冲区的C风格: char buf[12]; itoa(x, buf, 16); set_some_text(buf);

用以下代码替代:

class i2a
{
public:
    explicit i2a(int value) { ::sprintf(buf, "%d", value); }
    operator const char* () const { return buf; }
private:
    char buf[12];
};

// usage:
set_some_text(i2a(x));

(这样的类可以用于char<->wchar_t转换等)

我发现有些情况下这样的类会很危险: 例如,一个人可以编写

const char* someMeaningfulName = i2a(x);
// the right code should be i2a someMeaningfulName(x); or i2a someMeaningfulName = i2a(x);
set_some_text(someMeaningfulName);

在更复杂的情况下,接受文本的函数不会复制它,而是会在某个地方保存指向它的指针。例如,可能会这样做:
class Foo { .... const char* p; };
Foo f(const char* text) { ... foo.p = text; return foo; }

const char*变量不同,它可能不是很明显。

有没有办法使这些类更加安全?


更新:为什么不使用std::string、boost::lexical_cast、boost::format等:
代码应该在编译时使用-fno-except(禁用C++异常-无throw,无堆栈展开)时正常工作。同时,它应该在低内存条件下继续工作。
std::string和流使用堆分配的内存,而且至少会抛出bad_alloc异常。
当我们没有可用的堆内存时,通常我们仍然有一些千字节大小的堆栈(例如向用户写入我们已经用完内存,然后进行适当的清理)。


3
如果你的系统非常奇怪,以至于连最基本的C++类都无法使用,请更具体地说明。大多数显而易见的解决方案都无法在非真正的C++系统上运行。 - MSalters
"i2a someMeaningfulName(x);" 这里的 i2a 是什么?另一个类吗? - Ragesh Chakkadath
@rageshctech 哦,谢谢,是同一个类。(已修复) - Abyx
2个回答

0
如果您在本地变量中使用const char*,则可能会遇到麻烦。即使您像这样声明:const char* someMeaningfulName = std::string("foo").c_str();也是如此。
如果可以的话,应该像这样声明本地变量:
i2a someMeaningfulName(x);
set_some_text(someMeaningfulName);

你也可以考虑为 i2a 添加一个拷贝构造函数,以避免两个实例之间共享缓冲区。

0

ATL和MFC字符串转换宏也是这样编写的。直接像i2a(x)这样调用构造函数会创建一个临时对象,该对象将一直存在,直到传递给它的函数完成为止。因此,在这里:do_some(i2a(x)),临时对象将一直存在,直到do_some()完成。

请参阅msdn文档示例部分(示例2)。

在这里,

const char* someMeaningfulName = i2a(x);
set_some_text(someMeaningfulName);

这样做是行不通的,因为临时对象将在第一条语句上被释放。 someMeaningfulName 将成为垃圾。如果你觉得这缺乏安全性,我只能说:

这就是微软的做法!


如果有更好/更安全的方式,那就太好了,我同意! - Ragesh Chakkadath

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接