我需要使用的框架定义了一个简单的互斥类,它可以存储互斥锁所有者的名称,以帮助调试:
class mutex
{
public:
explicit mutex(const std::string& mutex_owner = "");
bool acquire() const;
bool release() const;
const std::string& get_name() const {return owner_name_;}
// ...
private:
std::string owner_name_;
// ...
};
我刚刚更改了一些算法,使互斥锁类型成为模板参数,因此如果不需要锁定,我可以为了性能原因传入这个算法:
class non_mutex
{
public:
explicit non_mutex(const std::string& mutex_owner = "") {}
bool acquire() const {return true;}
bool release() const {return true;}
std::string get_name() const {return "";}
};
由于这个没有存储名称(不需要调试),我更改了get_name()
成员函数以返回std::string
,而不是const std::string&
。
现在我的问题是:这个( 默默 )会破坏什么吗?代码编译得很好,并且似乎运行良好,但是在这个代码库中几乎没有测试,并且这个函数主要仅在出现问题时使用,而不是经常使用。
此更改可能导致运行时故障的情况如何?
请注意,这是一个C ++ 03环境,但我也对C ++ 11的答案感兴趣。
答案 0 :(得分:4)
按值返回的那个可能会抛出一个错误的alloc,引用一个是无抛出的。所以这可能是一个问题。
此外,他们有可能调用不同的重载,特征会有所不同,但我不担心这个。
答案 1 :(得分:1)
好吧,你不再回归常数了。你正在返回一个临时的。
理论上这可能会让用户误用返回值?也许?
顺便说一下。我会这样解决问题:
static std::string empty_string;
const std::string& get_name() const { return empty_string; }
答案 2 :(得分:1)
对于静默断点,一个区别是返回返回/引用的对象的生命周期。例如,请考虑以下代码:
const string &stupid_user(const string &s) { return s; }
const string &name = stupid_user(mtx.get_name());
mtx.acquire();
std::cout << name;
现在,如果mtx
的类型为mutex
,则会在acquire
之后打印互斥锁当前所有者的名称。如果mtx
具有类型non_mutex
,则它具有未定义的行为(在这种情况下,const引用不会延长临时的生命周期)。未明确的行为显然允许可能通过您的测试。
用不太愚蠢的用户:
const string &name = mtx.get_name();
mtx.acquire();
std::cout << name;
现在mutex
的行为是打印新的所有者,non_mutex
打印旧的所有者。也许你的测试会捕获它,也许它们没有,但是如果调用代码假定为一个并且你提供的类型是另一个类型,那么你已经默默地破坏了调用代码。
或者怎么样:
auto &&name = mtx.get_name();
mtx.acquire();
std::cout << name;
我认为这与非愚蠢用户的行为相同,但我不确定。
如果您(或此问题的未来访问者)对嘈杂的破损感兴趣,那么这取决于您如何定义允许使用Mutex概念的表达式(您希望您提供的两个类都满足)。
例如,如果允许表达式&mtx.get_name()
,那么non_mutex
就不能满足概念的要求。
如果您不允许该表达式,那么non_mutex
可能满足要求 - 请仔细查看允许调用get_name
的表达式。如果你所要求的只是它的返回值是“可转换为string
”或其他一些,那么你没事。
如果你没有根据允许的表达式定义模板参数的要求,而是根据它具有的成员函数签名和返回类型来定义,那么(a)你犯了一个错误,那不是模板的方式基于编译时的多态性应该起作用,(b)non_mutex
没有相同的成员函数签名和返回类型。
答案 3 :(得分:0)
我觉得您的更改没有任何问题。 get_name()
都返回不可修改的左值;尝试修改它们会导致C ++ 03中的编译器错误。
如果你想变得迂腐,你总是可以根据SFINAE做出选择,因为你已经模仿了代码。有了它,您可以完全删除non_mutex::get_name()
。