从const引用初始化非const对象时防止复制

时间:2010-11-29 04:27:57

标签: c++ reference const

我现在对C ++参考语义感到有点困惑。假设我有一个返回const引用的类:

class foo
{
private:
    std::map<int, int> stuff;
public:
    const std::map<int, int>& getStuff()
    {
        return stuff;
    }
};

我用它如下:

foo f;
const std::map<int, int>& s = f.getStuff();

这很好,但如果我按如下方式使用它:

foo f;
std::map<int, int> s = f.getStuff();

到底发生了什么?

如果我理解正确的话,会返回对stuff的const引用,并将副本创建到s,我可以对其造成严重破坏。有没有办法避免这种情况?

编辑:

所以没有办法避免在这里调用复制构造函数,对于std :: map反正......

4 个答案:

答案 0 :(得分:5)

简短回答:不,你无法阻止它。客户端不能修改原始文件,但是如果你给客户端读取地图的访问权限,那么客户端负责不用信息做蠢事;班级不可能阻止这一点。

更长的答案:也许,但不是真的。如果您确实想要复制困难,可以将地图包装在具有私有复制构造函数和赋值运算符的类中。这样s赋值将是非法的(编译器拒绝)。客户端仍然能够零散地读取地图元素并用它们填充新地图 - 手动复制 - 但防止这种情况的唯一方法是限制包装类中的读取访问权限,哪种类型挫败了getStuff的目的。

答案 1 :(得分:4)

std::map<int, int> s = f.getStuff();

这会调用std::map<int, int>复制构造函数并复制该对象。 stuff地图的内容将复制到新地图s

你不能对原始对象造成严重破坏,因为s是一个与原始对象完全无关的新对象,除了原始对象和新对象具有相同的内容这一事实。

通过stuff返回的const引用合法地破坏foo::getStuff()地图是不可能的。修改地图的唯一方法是通过const_cast,通过const_cast获得的指针或引用修改对象可能会产生未定义的行为。

答案 2 :(得分:1)

是的,您的理解是正确的。这不是复制初始化,而是涉及使用复制构造函数。无法避免此副本,因为这是您显示的代码段所要求的内容。

即使您对副本造成严重破坏,也不要担心。原件仍然安全。只有在创建副本的过程可能造成严重破坏时才会引起关注,但那是一个不同的问题。

C ++ 03相关参考文献:

  

$ 8.5 / 12-“初始化   发生在参数传递,函数中   返回,抛出异常(15.1),   处理异常(15.3),和   大括号括起初始化列表   (8.5.1)称为复制初始化   并且相当于形式T x =   一个;“

     

$ 8.5 / 14-“如果初始化是   直接初始化,或者如果是   复制初始化的地方   cv-不合格的源版本   type是和a相同的类   派生类,类的   目的地,建设者是   考虑。适用   构造函数是枚举的   (13.3.1.3),选择最好的一个   通过重载决议(13.3)。   调用所选的构造函数   初始化对象,用   初始化表达式为   参数(一个或多个)。如果没有构造函数   适用,或重载决议是   暧昧,初始化是   病态的“。

答案 3 :(得分:0)

是的,这将创建地图的副本。

至于你的问题 - 取决于你想要避免多少。一般来说,如果这是你自己声明的一个类,你可以使复制构造函数或operator =私有以防止它被使用,但很明显,这会禁止你做很多事情。