提问人:sbi 提问时间:11/12/2012 最后编辑:sbi 更新时间:11/12/2012 访问量:148
在返回副本而不是常量引用时,我会中断代码吗
Will I break code when returning a copy instead of a const reference
问:
我需要使用的框架定义了一个简单的互斥类,该类可以存储互斥锁所有者的名称,以帮助调试:
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 的答案感兴趣。
答:
好吧,您不再返回常量。您返回的是临时的。
从理论上讲,这可能会允许用户滥用返回值?也许?
顺便说一句。我会以这种方式解决问题:
static std::string empty_string;
const std::string& get_name() const { return empty_string; }
评论
empty_string
empty_string
按值返回的那个可能会抛出错误的分配,引用的那个是 no-throw。所以这可能是一个问题。
此外,他们有可能调用不同的重载,并且特征会以不同的方式专门化,但我不会担心这一点。
评论
std::string
std::non_mutex::get_name()
对于静默破损,一个区别是返回/返回所引用的对象的生存期。例如,请考虑以下代码:
const string &stupid_user(const string &s) { return s; }
const string &name = stupid_user(mtx.get_name());
mtx.acquire();
std::cout << name;
现在,如果 have type,则会在 .如果 have type,则它具有未定义的行为(在这种情况下,const 引用不会延长临时的生存期)。未定义的行为显然允许它通过您的测试。mtx
mutex
acquire
mtx
non_mutex
对于不那么愚蠢的用户:
const string &name = mtx.get_name();
mtx.acquire();
std::cout << name;
现在的行为是打印新所有者,打印旧所有者。也许你的测试捕捉到了这一点,也许它们没有,但是如果调用代码假设了一个,并且你提供了一个类型,它是另一个类型,那么你就默默地破坏了调用代码。mutex
non_mutex
或者怎么样:
auto &&name = mtx.get_name();
mtx.acquire();
std::cout << name;
我认为这与非愚蠢的用户的行为相同,但我不确定。
如果你(或这个问题的未来访问者)对嘈杂的破损感兴趣,那么这取决于你如何定义允许使用的表达式,以便使用你的互斥概念(你希望你提出的两个类都满足)。
例如,如果允许表达式,则不满足概念的要求。&mtx.get_name()
non_mutex
如果不允许该表达式,那么也许确实满足了要求 -- 仔细查看允许哪些表达式涉及对 的调用。如果你所需要的只是它的返回值是“可转换为”或类似的东西,那么你就没问题了。non_mutex
get_name
string
如果您没有根据允许的表达式定义模板参数的要求,而是根据它所具有的成员函数签名和返回类型来定义,那么 (a) 您犯了一个错误,这不是基于模板的编译时多态性应该如何工作,并且 (b) 没有相同的成员函数签名和返回类型。non_mutex
评论
+1
auto
non_mutex
const
mtx
我不觉得你的更改有任何问题。两者都返回不可修改的左值;尝试修改它们会导致 C++03 中的编译器错误。get_name()
如果你想迂腐,你总是可以根据 SFINAE 做出选择,因为你已经模板化了代码。有了它,您可以完全删除 .non_mutex::get_name()
评论
mutex::get_name
不返回右值,而是返回不可修改的左值。
评论