- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我正在尝试理解 move 语义和复制/move 省略。
我想要一个包含一些数据的类。我想在构造函数中传递数据,我想拥有这些数据。
看完this , this和 this我的印象是,在 C++11 中,如果我想存储一个拷贝,那么按值传递应该至少与任何其他选项一样有效(除了增加代码大小的小问题)。
然后如果调用代码想避免复制,它可以通过传递右值而不是左值来实现。 (例如使用 std::move)
所以我试了一下:
#include <iostream>
struct Data {
Data() { std::cout << " constructor\n";}
Data(const Data& data) { std::cout << " copy constructor\n";}
Data(Data&& data) { std::cout << " move constructor\n";}
};
struct DataWrapperWithMove {
Data data_;
DataWrapperWithMove(Data&& data) : data_(std::move(data)) { }
};
struct DataWrapperByValue {
Data data_;
DataWrapperByValue(Data data) : data_(std::move(data)) { }
};
Data
function_returning_data() {
Data d;
return d;
}
int main() {
std::cout << "1. DataWrapperWithMove:\n";
Data d1;
DataWrapperWithMove a1(std::move(d1));
std::cout << "2. DataWrapperByValue:\n";
Data d2;
DataWrapperByValue a2(std::move(d2));
std::cout << "3. RVO:\n";
DataWrapperByValue a3(function_returning_data());
}
输出:
1. DataWrapperWithMove:
constructor
move constructor
2. DataWrapperByValue:
constructor
move constructor
move constructor
3. RVO:
constructor
move constructor
我很高兴在这些情况下都没有调用复制构造函数,但为什么在第二种情况下调用了一个额外的 move 构造函数?我想 Data
的任何像样的 move 构造函数都应该非常快,但它仍然让我烦恼。我很想改用按右值引用传递(第一个选项),因为这似乎会减少一次 move 构造函数调用,但如果可以的话,我想采用按值传递和复制省略。
最佳答案
DataWrapperByValue::data_
是从 DataWrapperByValue::DataWrapperByValue(Data data)
的参数 data
中移出的,它是从 中移入的d2
。
对于获得左值的情况,您得出的按右值引用传递的结论以及按值版本会产生最佳性能。然而,这被广泛认为是过早的优化。 Howard Hinnant ( Best way to write constructor of a class who holds a STL container in C++11 ) 和 Sean Parent ( http://channel9.msdn.com/Events/GoingNative/2013/Inheritance-Is-The-Base-Class-of-Evil ) 都注意到他们认为这种过早的优化。原因是 move 应该非常便宜并且在这种情况下避免它们会导致代码重复,特别是如果您有多个参数可以是 r 或 l 值。如果通过概要分析或测试您发现这确实会降低性能,您总是可以在事后轻松添加右值传递引用。
在您确实需要额外性能的情况下,一个有用的模式是:
struct DataWrapperByMoveOrCopy {
Data data_;
template<typename T,
typename = typename std::enable_if< //SFINAE check to make sure of correct type
std::is_same<typename std::decay<T>::type, Data>::value
>::type
>
DataWrapperByMoveOrCopy(T&& data) : data_{ std::forward<T>(data) } { }
};
这里的构造函数总是做正确的事情,正如我的实例所示:http://ideone.com/UsltRA
这种有争议的复杂代码的优势可能与单个参数无关,但想象一下,如果您的构造函数有 4 个参数(可能是 r 值或 l 值),这比编写 16 个不同的构造函数要好得多。
struct CompositeWrapperByMoveOrCopy {
Data data_;
Foo foo_;
Bar bar_;
Baz baz_;
template<typename T, typename U, typename V, typename W,
typename = typename std::enable_if<
std::is_same<typename std::decay<T>::type, Data>::value &&
std::is_same<typename std::decay<U>::type, Foo>::value &&
std::is_same<typename std::decay<V>::type, Bar>::value &&
std::is_same<typename std::decay<W>::type, Baz>::value
>::type
>
CompositeWrapperByMoveOrCopy(T&& data, U&& foo, V&& bar, W&& baz) :
data_{ std::forward<T>(data) },
foo_{ std::forward<U>(foo) },
bar_{ std::forward<V>(bar) },
baz_{ std::forward<W>(baz) } { }
};
请注意,您可以省略 SFINAE 检查,但这会导致一些细微的问题,例如使用显式构造函数进行隐式转换。同样,在不检查参数类型的情况下,转换被推迟到构造函数内部,那里有不同的访问权限、不同的 ADL 等。请参见实际示例:http://ideone.com/yb4e3Z
关于c++ - 传递值导致额外 move ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22425679/
我配置了我的RouteInitializer如下: class AppRouteInitializer implements RouteInitializer { init(Router rout
我正在尝试从 Android 应用程序发送短信。我正在使用 PendingIntent 以便我可以使用 Broadcast Receiver 检查它是否发送正常。由于 sendTextMessage
目录 简介 1 "额外"字段是什么 1.1 "额外"是指与业务无关 1.2 产生
应用程序读取 JSON 数据。然后它会将其放入 ListView (正确),但在按下某个项目后,我总是会得到显示的相同值。下面的代码我认为是问题所在,但我找不到。 try{ JSONArray
我正在使用以下代码 (Kotlin) 创建通知 val builder = NotificationCompat.Builder(ctx) ........ .set
我有一个问题。现在我正在使用 3 个面板,mainPanel 和其他 2 个面板(btnPanel 和 iconPanel)。所以问题是当我按下“重置”按钮时,我删除了 iconPanel 并再次添加
这是我的 html: Settings Export Import 和CSS: span.button { float:right; margin-righ
我正在尝试将一个结构编码为 JSON,然后将其插入我的 Mongo 数据库,但不断出现此错误:%!(EXTRA main.Test={575590180 Me})。我究竟做错了什么?我完全从我从事的另
嘿,我遇到了这些 latex 格式问题,有人可以提供一些帮助吗? .tex 文件: \begin{table}{} \renewcommand{\arraystretch}{1.1} \c
我在 FragmentPagerAdapter 中使用了 Fragment 的 ArrayList。 我想在 saveState() 中保存此 ArrayList 的状态,并在 restoreStat
我做了this MapKit-教程 一切正常,但如何为我的 pin 添加额外的属性? 这是我的课车: import Foundation import MapKit class Car: NSObje
关于 Android intent 将提供的附加功能有哪些文档? 更新: 我做了一些进一步的调查。我知道我们可以假设每个 Intent 都不会解析任何数据或额外内容,除非有明确记录。此外,一些(但不是
我在 python3.4.3 上使用 SqlAlchemy 来管理 MySQL 数据库。我正在创建一个表: from datetime import datetime from sqlalchemy
我正在使用 bootstrap 创建网页。我在两个 block (内容和标题)上派生了正文。在内容 block 中,我有 div 类 .container .sameTable 在里面我有 div 类
我在Windows 7上的MinGW和MSYS下使用gfortran构建了一些fortran程序。但是当我在未安装MinGW和MSYS的其他计算机上运行它们时,系统总是要求一些dll,例如libgfo
第一个元素的右侧似乎有额外的间距,我不知道它是从哪里来的。有人可以帮助我吗? 这是我使用的代码: http://jsfiddle.net/srabeat/tenx4y1c/1/ for (i = 0;
我使用 fs-extra 收到以下错误: ERROR { [Error: EPERM: operation not permitted, unlink 'C:\Projects\xxx\branche
我正在尝试在 CBC 模式下使用 AES-128 加密 320 字节的二进制数据,并将密码存储到一个文件中。输出文件应该是 320 字节,但我得到了 336 字节。这是我的代码: #include
我有一个特定的要求,我必须从我的 Activity 中触发浏览器上的 url。我可以使用以下代码执行此操作: Intent browserIntent = new Intent( Intent.A
我正在使用 JMS DI 注入(inject)带有注解的服务: use JMS\DiExtraBundle\Annotation as DI; /** * @DI\Service("foo.bar.
我是一名优秀的程序员,十分优秀!