1

我的类有一个具有以下原型的方法:

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 的作者,我如何防止这样的滥用行为?或者有没有办法我可以以某种方式支持这种用法?

更新1:直到我更改了映射的实现,从直接保存值到保存“内存引用”——长度和指向缓冲区的指针,这个错误才被发现。但是get_field总是返回一个字符串——不是 astring*string&a——所以我假设它总是返回一个临时的。我不明白为什么它之前没有中断(我也很尴尬;我声称我的更改不会影响 API)。

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

更新 2:似乎有可能(参考更新 1),刚才出现错误的原因是我的“幕后”更改要求我将以下开关添加到 g++ 4.4.7:-std=gnu+ +0x,这可能影响了临时对象的回收方式。

4

2 回答 2

3

Mostly you have to assume that users of your code are competent.

But this is a political world. So maybe sometimes you may have to do a probabilistic best effort to prevent mishaps. E.g.,

#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.
}

Maybe throw in a move constructor there for good measure, but generally perfect efficiency is in conflict with perfect safety and perfect clarity, e.g. can has 2 but not 3.

于 2013-12-27T01:29:11.447 回答
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
}

但至少一个内存检查器会找到他们的分配而不是你的

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

于 2013-12-27T01:36:59.433 回答