Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/127.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从常量引用初始化非常量对象时防止复制 我现在对C++引用语义有点困惑。假设我有一个返回常量引用的类: class foo { private: std::map<int, int> stuff; public: const std::map<int, int>& getStuff() { return stuff; } }; class-foo { 私人: 地图资料; 公众: const std::map&getStuff() { 归还物品; } };_C++_Reference_Constants - Fatal编程技术网

从常量引用初始化非常量对象时防止复制 我现在对C++引用语义有点困惑。假设我有一个返回常量引用的类: class foo { private: std::map<int, int> stuff; public: const std::map<int, int>& getStuff() { return stuff; } }; class-foo { 私人: 地图资料; 公众: const std::map&getStuff() { 归还物品; } };

从常量引用初始化非常量对象时防止复制 我现在对C++引用语义有点困惑。假设我有一个返回常量引用的类: class foo { private: std::map<int, int> stuff; public: const std::map<int, int>& getStuff() { return stuff; } }; class-foo { 私人: 地图资料; 公众: const std::map&getStuff() { 归还物品; } };,c++,reference,constants,C++,Reference,Constants,我的用法如下: foo f; const std::map<int, int>& s = f.getStuff(); foo f; std::map<int, int> s = f.getStuff(); foof; const std::map&s=f.getStuff(); 这很好,但如果我按如下方式使用它: foo f; const std::map<int, int>& s = f.getStuff(); foo f; std:

我的用法如下:

foo f;
const std::map<int, int>& s = f.getStuff();
foo f;
std::map<int, int> s = f.getStuff();
foof;
const std::map&s=f.getStuff();
这很好,但如果我按如下方式使用它:

foo f;
const std::map<int, int>& s = f.getStuff();
foo f;
std::map<int, int> s = f.getStuff();
foof;
std::map s=f.getStuff();
到底发生了什么

如果我理解正确,则返回了对
内容的常量引用,并在
s
中创建了一个副本,我可以对其造成严重破坏。有什么办法可以避免这种情况吗

编辑:

因此,这里无法避免调用复制构造函数,因为std::map无论如何…

std::map s=f.getStuff();
std::map<int, int> s = f.getStuff();
这将调用
std::map
copy构造函数并创建对象的副本。
stuff
映射的内容将复制到新映射
s

您不能破坏原始对象,因为除了原始对象和新对象具有相同的内容之外,
s
是一个与原始对象完全无关的新对象


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

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

即使你破坏了这本书,也不要担心。原件仍然安全。问题是,只有在创建副本的过程可能造成严重破坏的情况下,这才是另一个问题

C++03相关参考文献:

$8.5/12-“初始化 在参数传递、函数中发生 返回,抛出异常(15.1), 处理异常(15.3),以及 括号内的初始值设定项列表 (8.5.1)称为复制初始化 与形式tx等价= a、 "

$8.5/14-“如果初始化是 直接初始化,或者如果是 复制初始化,其中 cv源的不合格版本 类型与或类型是同一类 的派生类 目的地,构造函数是 已考虑。适用的 构造函数被枚举 (13.3.1.3),并选择最好的 通过过载分辨率(13.3)。 这样选择的构造函数称为 要初始化对象,请使用 初始值设定项表达式作为其 参数。如果没有构造函数 应用,或重载分辨率为 不明确,初始化是 格式不正确。”


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


至于你的问题-取决于你想避免多少。一般来说,如果这是您自己声明的类,您可以将复制构造函数或
运算符设置为私有以防止使用它,但显然,这将禁止您执行许多操作。

简短回答:不,您不能阻止它。客户机不能修改原始地图,但如果您给客户机对地图的读取权限,那么客户机有责任不使用这些信息做愚蠢的事情;班级不可能阻止这一切


更长的回答:可能,但不是真的。如果您确实想使复制变得困难,可以将映射包装在一个带有私有复制构造函数和赋值运算符的类中。这样,
s
赋值将是非法的(被编译器拒绝)。客户端仍然能够逐段读取映射的元素,并用它们填充一个新映射(手动副本),但防止这种情况发生的唯一方法是限制包装器类中的读取访问,哪种方法违背了
getStuff

AFAIK的目的?复制构造函数将被调用,我看不到避免这种情况的方法。你是对的。但是,如果你想阻止自己这样做,你可以总是使
s
const。同时,将
s
设为常量ref意味着您需要确保
f
在此期间保持活动状态——如果它是先前声明的自动变量,则这将自动发生,但是,如果它是在堆上创建的,则需要进行管理。但是,对
s
执行的任何修改都不会影响原始对象
stuff
。那么它是如何影响您的呢?与其返回对映射的引用,不如直接返回常量迭代器以开始()和结束()?问题解决了。不需要编写一堆包装器代码。@John:如果OP想要使用
std::map
特定的功能,如
{upper,lower}\u-bound
find
,那么这不是一个真正有用的解决方案。因此,如果OP对引用语义有点困惑,引用该标准可能有点霸道……令人惊讶的是,这么多的选票,尽管它没有回答“有什么办法可以避免这种情况吗?”的问题。公平地说,我想它要么使用引用,要么去
const std::map s=f.getStuff()then@Chubsdad:不,我是在解决OP的元问题“这行代码到底是如何工作的?”一旦你发现原始对象是完整复制的,并且新对象除了具有相同的内容外,与原始对象完全无关,这应该很简单。@vic:对。调用代码是否可以修改它所创建的副本应由调用代码决定。如果调用方希望调用
foo::getStuff()
,复制映射,并破坏该副本,
foo