C++ 当返回副本而不是常量引用时,是否会中断代码

C++ 当返回副本而不是常量引用时,是否会中断代码,c++,C++,我需要使用的框架定义了一个简单的互斥对象类,该类可以存储互斥对象所有者的名称,以帮助调试: 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_;}

我需要使用的框架定义了一个简单的互斥对象类,该类可以存储互斥对象所有者的名称,以帮助调试:

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; }

按值返回的可能会抛出错误的alloc,而引用的可能不会抛出。所以这可能是个问题


此外,它们可能会调用不同的重载,而trait会以不同的方式专门化,但我不担心这一点。

对于无声中断,一个区别是返回/引用的对象的生存期。例如,考虑下面的代码:

const string &stupid_user(const string &s) { return s; }

const string &name = stupid_user(mtx.get_name());
mtx.acquire();
std::cout << name;
现在,
mutex
的行为是打印新所有者,而
non_mutex
则打印旧所有者。可能您的测试捕捉到了这一点,但可能没有,但是如果调用代码假设了一个类型,并且您提供了另一个类型,那么您已经悄悄地破坏了调用代码

或者:

auto &&name = mtx.get_name();
mtx.acquire();
std::cout << name;
auto&&name=mtx.get_name();
mtx.acquire();

我觉得你的改变没有任何问题。这两个
get_name()
都返回不可修改的左值;试图修改它们会导致C++03中的编译器错误


如果你想学究化,你可以根据SFINAE做出选择,因为你已经模板化了代码。这样,您就可以完全删除
非互斥体::get_name()

注意,这有不同的线程安全要求,因为多个互斥体将返回相同名称的对象引用。@johanneschaub litb这对常量对象有影响吗?@Let_Me_Be:可能
空字符串
应该是常量对象-P但我认为你是对的,只要没有人修改
空字符串
,就不应该有任何特殊的线程问题。无意冒犯,但这是非常模糊的。前四句话中的三句只是重复了我在问题中已经说过的话,第四句暗示可能有什么,我想知道可能有什么。谢谢您的提示,我们正在解决一个问题,但我来这里询问的原因正是因为我想知道这是否必要。@sbi好吧,这就是为什么我们有向上投票和向下投票按钮:-)
mutex::get_name
不返回右值,它返回一个不可修改的左值。我知道如何修复暴露问题的代码。我只是担心我可能会错过那些在编译时不会发出声音,但在运行时失败的代码。考虑到我们这里还没有右值引用,调用不同重载的可能性有多大?(我担心的正是那些有问题的孩子。这是一个可以全天候运行的小设备。)你可能会很幸运:如果你的
std::string
有一个小字符串优化,那么我认为
std::non_mutex::get_name()
应该不会出现在你的实现中。当我写“静默”时,我的意思是它不会导致任何编译错误,因为我不担心这些错误。编译失败时,可以修复依赖返回值作为引用的代码。我担心编译的代码可能会在运行时失败。因此,这种“无声”甚至可能指的是惊人的错误。(顺便说一句,我没有问如何修复依赖于结果作为引用的代码,我问的是这可能是什么类型的代码。
+1
,关于您给出的一个示例,请注意:正如我所做的那样(姗姗来迟)在问题中写道,该平台没有C++11编译器,因此我们无法从
auto
中获益。也许我只是有一个心理上的失误,但这两个示例(在您的答案末尾)不是都会因为
非互斥体
而失败吗?我的意思是,获得一个引用(打赌
const
或r-value)对临时用户的修改不会延长临时用户的使用寿命。因此,这将导致未定义的行为,而不是打印旧用户。@sbi:我的三个代码片段不是为了相互更正,它们应该是三个类似的代码示例,它们的定义行为根据
mtx
的类型而不同。因为如果不使用C++11编译器,您可以有理由相信最后一个编译器不会出现在您的代码库中,但前两个编译器中的任何一个都可能:-)@Let_Me_be:“获取对临时对象的引用不会延长临时对象的生存时间”--是的,如果您将引用绑定到临时对象,它会延长临时对象的生存时间。C++03中的12.2/5。
auto &&name = mtx.get_name();
mtx.acquire();
std::cout << name;