- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我在理解 C++ 中对象所有权的概念时遇到问题。
为了让您了解一些背景知识,我正在使用 Visual Studio 2013 在 Windows 上使用 SFML 2.1 在 C++ 11 中编写一个小应用程序。
基本上我写了一个类 AssetsManager
来环绕我的 sf::Texture
对象。我想将我的纹理存储在 std::map
中,以便能够使用一个键轻松地引用和找到它们。该 map 是 AssetsManager
类的私有(private)成员。
我有两个公共(public)成员函数,用于将纹理对象“注册”(添加)到 map 和从 map 获取纹理对象。
这是我在类头中声明 map 的方式:
private:
// Resources are mapped to a key for easy access.
std::map < std::string, sf::Texture > m_textures;
这是cpp文件中的两个函数定义:
sf::Texture AssetsManager::GetTexture(const std::string& key)
{
return m_textures[key];
}
bool AssetsManager::RegisterTexture(const std::string& key, const sf::Texture& texture)
{
// If a texture in the std::map already exists with the given key, return false.
if (m_textures.count(key))
return false;
// Add the texture with key to the std::map.
m_textures.insert(std::make_pair(key, texture));
return true;
}
在我的主要功能中,我这样做:
AssetsManager assets;
sf::Texture myTexture;
myTexture.loadFromFile("Assets/MyCharacter.png");
assets.RegisterTexture("Hero Character", myTexture);
我不明白的是在我的主函数中声明的 myTexture
变量发生了什么。我将对象添加到 map 中,所以我可以通过调用
assets.GetTexture("Hero Character");
我可以在 main 函数中使用 myTexture
变量做些什么吗?
两个对象是同一个吗?或者所有权是否从 myTexture
转移到 map 中的对象,从而使 myTexture
变得有点空?
如果有人能澄清这一点,那就太好了,这样我就可以继续我的工作了。
如果在这里使用指针是正确的选择,我什至会犹豫不决,但我希望 AssetsManager
能够完全控制 Textures,即“拥有”它们,而不仅仅是指向对象的指针,如果你明白我的意思的话。
最佳答案
逐步分析:
m_textures.insert(std::make_pair(key, texture));
首先,std::make_pair(T&&, U&&)
takes forwarding-references,并实例化一对 decayed类型:std::pair<std::decay_t<T>, std::decay_t<U>>
从提供的参数。在您的情况下,这些类型如下:
T = const std::string&, std::decay_t<T> = std::string
U = const sf::Texture&, std::decay_t<U> = sf::Texture
话虽如此,该对定义为 std::pair<std::string, sf::Texture>
,并且由于原始值是const lvalue references,所以两个参数都是key
和 texture
已被复制构建,因此拷贝已存储在返回的 std::pair
的实例中.
现在,insert
成员函数。 std::map
有它的overload取另一个forwarding-reference,描述如下:
Value to be copied to (or moved as) the inserted element.
也就是说,insert
的论点(推导类型 P = std::pair<std::string, sf::Texture>
,带 P&&
)是 std::forward<P>
编辑到新创建的节点对,您的 std::map
实例商店。这导致移动你的对,描述为:
The object is initialized with the contents of the pr
pair
object. The corresponding member of pr is passed to the constructor of each of its members.
但是,如果这些成员中的任何一个没有实现移动构造函数,操作将退回到该特定成员的常规复制构造。
总结一下,用m_textures.insert(std::make_pair(key, texture));
在最坏情况中声明,您最终可能会得到两个(可能是昂贵的)两个论点的拷贝。唯一的好处是您不必担心所有权,因为std::map
本身获得了这些元素的全新拷贝。附带说明一下,当有人通过引用 获取您的对象时,您实际上永远不必担心所有权。甚至不太可能有人会考虑存储对此类对象的引用或地址,因为它的来源是未知的,而且人们无法控制它的生命周期。
您可以尝试优化此操作,将其替换为以下 emplace
成员函数的调用:
m_textures.emplace(std::piecewise_construct
, std::forward_as_tuple(key)
, std::forward_as_tuple(texture));
这将使用参数将一对直接放置到关联的节点中。
尽管如此,我觉得你应该使用 std::shared_ptr
对于 sf::Texture
实例,因为顾名思义,它可以存储大量数据。
此外,考虑重新实现您的 GetTexture
成员函数(具有重载的 const-qualified 一个)返回reference:
sf::Texture& AssetsManager::GetTexture(const std::string& key)
//~~~~~~~~~^
{
return m_textures[key];
}
const sf::Texture& AssetsManager::GetTexture(const std::string& key) const
//~~~~~~~~~~~~~~~^ ~~~~^
{
return m_textures.at(key);
}
因为否则每次调用 GetTexture
也会制作拷贝。
关于c++ - 当通过 const 引用传递的对象被添加到像 std::map 这样的容器时会发生什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26430146/
尝试使用集成到 QTCreator 的表单编辑器,但即使我将插件放入 QtCreator.app/Contents/MacOS/designer 也不会显示。不过,相同的 dylib 文件确实适用于独
在此代码示例中。 “this.method2();”之后会读到什么?在返回returnedValue之前会跳转到method2()吗? public int method1(int returnedV
我的项目有通过gradle配置的依赖项。我想添加以下依赖项: compile group: 'org.restlet.jse', name: 'org.restlet.ext.apispark', v
我将把我们基于 Windows 的客户管理软件移植到基于 Web 的软件。我发现 polymer 可能是一种选择。 但是,对于我们的使用,我们找不到 polymer 组件具有表格 View 、下拉菜单
我的项目文件夹 Project 中有一个文件夹,比如 ED 文件夹,当我在 Eclipse 中指定在哪里查找我写入的文件时 File file = new File("ED/text.txt"); e
这是奇怪的事情,这个有效: $('#box').css({"backgroundPosition": "0px 250px"}); 但这不起作用,它只是不改变位置: $('#box').animate
这个问题在这里已经有了答案: Why does OR 0 round numbers in Javascript? (3 个答案) 关闭 5 年前。 Mozilla JavaScript Guide
这个问题在这里已经有了答案: Is the function strcmpi in the C standard libary of ISO? (3 个答案) 关闭 8 年前。 我有一个问题,为什么
我目前使用的是共享主机方案,我不确定它使用的是哪个版本的 MySQL,但它似乎不支持 DATETIMEOFFSET 类型。 是否存在支持 DATETIMEOFFSET 的 MySQL 版本?或者有计划
研究 Seam 3,我发现 Seam Solder 允许将 @Named 注释应用于包 - 在这种情况下,该包中的所有 bean 都将自动命名,就好像它们符合条件一样@Named 他们自己。我没有看到
我知道 .append 偶尔会增加数组的容量并形成数组的新副本,但 .removeLast 会逆转这种情况并减少容量通过复制到一个新的更小的数组来改变数组? 最佳答案 否(或者至少如果是,则它是一个错
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
noexcept 函数说明符是否旨在 boost 性能,因为生成的对象中可能没有记录异常的代码,因此应尽可能将其添加到函数声明和定义中?我首先想到了可调用对象的包装器,其中 noexcept 可能会产
我正在使用 Angularjs 1.3.7,刚刚发现 Promise.all 在成功响应后不会更新 angularjs View ,而 $q.all 会。由于 Promises 包含在 native
我最近发现了这段JavaScript代码: Math.random() * 0x1000000 10.12345 10.12345 >> 0 10 > 10.12345 >>> 0 10 我使用
我正在编写一个玩具(物理)矢量库,并且遇到了 GHC 坚持认为函数应该具有 Integer 的问题。是他们的类型。我希望向量乘以向量以及标量(仅使用 * ),虽然这可以通过仅使用 Vector 来实现
PHP 的 mail() 函数发送邮件正常,但 Swiftmailer 的 Swift_MailTransport 不起作用! 这有效: mail('user@example.com', 'test
我尝试通过 php 脚本转储我的数据,但没有命令行。所以我用 this script 创建了我的 .sql 文件然后我尝试使用我的脚本: $link = mysql_connect($host, $u
使用 python 2.6.4 中的 sqlite3 标准库,以下查询在 sqlite3 命令行上运行良好: select segmentid, node_t, start, number,title
我最近发现了这段JavaScript代码: Math.random() * 0x1000000 10.12345 10.12345 >> 0 10 > 10.12345 >>> 0 10 我使用
我是一名优秀的程序员,十分优秀!