指向临时对象的指针 - 如何防止它?

时间:2013-12-27 00:51:43

标签: c++ pointers temporary-objects

我的班级有一个方法,其中包含以下原型:

std::string
Block::get_field(std::string rec_type, std::string field) { ... }

它从地图中检索一个值,将其转换为字符串,然后返回该字符串。

有人使用我的课程如下:

char * buf = block.get_field(my_rec, my_field).c_str();

除非我弄错了,否则设置buf指向一个临时字符串。不久之后,当他看到* buf时,它已经损坏了。

显然我更喜欢我的用户写道:

std::string buf = block.get_field(my_rec, my_field);

Block的作者如何防止这样的滥用?或者我有办法以某种方式支持这种用法吗?

UPDATE 1:直到我改变了地图的实现,从直接保存值到保存“内存引用” - 长度和指向缓冲区的指针之后,才发现这个错误。但是get_field总是返回一个字符串 - 而不是string*string& - 所以我认为它总是返回一个临时字符串。我不明白为什么它没有破坏(我也很尴尬;我声称我的更改不会影响API)。

我准备通知用户他必须修改他的代码,但我希望能够引用他破坏的“规则”,并可能解释他之前是如何“幸运”的

更新2:似乎有可能(在参考更新1中),刚出现错误的原因是我的“引擎盖下”更改需要我添加以下开关g ++ 4.4.7: -std = gnu ++ 0x ,这可能会影响临时工的回收方式。

2 个答案:

答案 0 :(得分:3)

大多数情况下,您必须假设代码的用户才有能力。

但这是一个政治世界。所以有时候你可能不得不做一个概率性的最佳努力来防止意外事故。如,

#include <assert.h>
#include <string>

class StdString: public std::string
{
private:
    using std::string::c_str;
    using std::string::data;
public:
    StdString( char const* const s ): std::string( s ) { assert( s != nullptr ); }
};

StdString foo() { return "Bah!"; }

int main()
{
    std::string const   a = foo();
    char const* const   b = foo().c_str();      //! Nyet.
}

也许在那里投入移动构造函数以获得良好的衡量标准,但通常完美的效率与完美的安全性和完美的清晰度相冲突,例如:可以有2但不是3。

答案 1 :(得分:2)

你真的不应该阻止它,但如果你发现这种情况发生了很多,你可以将原型改为:

void
Block::get_field(std::string& ret, std::string rec_type, std::string field) { ... }

引用一个引用:std::string& ret将强制一个std :: string存在,然后再调用你的方法,而他们仍然可以做一些事情来破坏他们的内存,它将在“他们的代码”中发生。像这个糟糕的代码一样简单的东西很难防止:

char * foo()
{
    std::string buffStr;
    block.get_field(bufStr, my_rec, my_field)
    return buffStr.c_str();         // DO NOT DO THIS - Example of bad code
}

但至少有一个mem checker会找到他们的分配而不是你的分配

更新1: c_str()返回的内存的生命周期是生成它的string的生命周期,除非更改string,在这种情况下,生命周期可能会结束。基本上,它是未定义的行为,有时可能有效,而不是其他行为。您的更改可能已更改观察到的行为,但用户代码从未符合。其他因素也可能打破它。基本上,它总是被打破,从你的描述中似乎没有理由道歉。