- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
相关问题:
我发布这个问题是因为 move 语义这个东西真的让我感到困惑。起初它们对我来说似乎很清楚,但当我试图向自己演示它们的用法时,我意识到也许我误解了什么。
我已经尝试将以下文件安排为一个使用 move 语义的类 vector 类的不那么简单的实现(实际上还有一个 main
函数,以及一个自由函数来使打印到屏幕更容易,...)。这并不是一个真正的最小工作示例,但它在屏幕上产生的输出是合理可读的,恕我直言。
不过,如果您认为最好将它瘦下来,请建议我该怎么做。
无论如何,代码如下,
#include<iostream>
using namespace std;
int counter = 0; // to keep count of the created objects
class X {
private:
int id = 0; // hopefully unique identifyier
int n = 0;
int * p;
public:
// special member functions (ctor, dtor, ...)
X() : id(counter++), n(0), p(NULL) { cout << "default ctor (id " << id << ")\n"; }
X(int n) : id(counter++), n(n), p(new int[n]) { cout << "param ctor (id " << id << ")\n"; };
X(const X& x) : id(counter++), n(x.n), p(new int[n]) {
cout << "copy ctor (id " << id << ") (allocating and copying " << n << " ints)\n";
for (int i = 0; i < n; ++i) {
p[i] = x.p[i];
}
};
X(X&& x) : id(counter++), n(x.n), p(x.p) {
cout << "move ctor (id " << id << ")\n";
x.p = NULL;
x.n = 0;
};
X& operator=(const X& x) {
cout << "copy assignment (";
if (n < x.size() && n > 0) {
cout << "deleting, ";
delete [] p;
n = 0;
}
if (n == 0) {
cout << "allocating, and ";
p = new int[n];
}
n = x.size();
cout << "copying " << n << " values)";
for (int i = 0; i < n; ++i) {
p[i] = x.p[i];
}
cout << endl;
return *this;
};
X& operator=(X&& x) {
this->n = x.n;
this->p = x.p;
x.p = NULL;
x.n = 0;
cout << "move assignment (\"moving\" " << this->n << " values)\n";
return *this;
};
~X() {
cout << "dtor on id " << id << " (array of size " << n << ": " << *this << ")\n";
delete [] p;
n = 0;
}
// getters/setters
int size() const { return n; }
// operators
int& operator[](int i) const { return p[i]; };
X operator+(const X& x2) const {
cout << "operator+\n";
int n = min(x2.size(), this->size());
X t(n);
for (int i = 0; i < n; ++i) {
t.p[i] = this->p[i] + x2.p[i];
}
return t;
};
// friend function to slim down the cout lines
friend ostream& operator<<(ostream&, const X&);
};
int main() {
X x0;
X x1(5);
X x2(5);
x1[2] = 3;
x2[3] = 4;
cout << "\nx0 = x1 + x2;\n";
x0 = x1 + x2;
cout << "\nX x4(x1 + x2);\n";
X x4(x1 + x2);
cout << x4 << endl;
cout << '\n';
}
// function to slim down the cout lines
ostream& operator<<(ostream& os, const X& x) {
os << '[';
for (int i = 0; i < x.size() - 1; ++i) {
os << x.p[i] << ',';
}
if (x.size() > 0) {
os << x.p[x.size() - 1];
}
return os << ']';
}
当我编译并运行它时
$ clear && g++ moves.cpp && ./a.out
输出如下(#
- 手动添加注释)
default ctor (id 0)
param ctor (id 1)
param ctor (id 2)
x0 = x1 + x2;
operator+
param ctor (id 3)
move assignment ("moving" 5 values)
dtor on id 3 (array of size 0: [])
X x4(x1 + x2);
operator+
param ctor (id 4)
[0,0,3,4,0]
dtor on id 4 (array of size 5: [0,0,3,4,0])
dtor on id 2 (array of size 5: [0,0,0,4,0])
dtor on id 1 (array of size 5: [0,0,3,0,0])
dtor on id 0 (array of size 5: [0,0,3,4,0])
从输出的第一部分来看,我想我确实展示了 move 赋值运算符的预期用途。在这方面我是对的吗? (从下一个输出来看,我似乎不是,但我不确定。)
在这一点上,如果我关于复制省略阻止了对复制构造器的调用的推论是正确的,那么一个问题对我来说很自然 (and not only me, see OP's comment here):
基于另一个临时对象(例如 x4
基于 x1 + x2
中的 X x4(x1 + x2);
的结果)创建对象的情况不正是将语义 move 到应该引入的地方?如果不是,展示 move 构造器用法的基本示例是什么?
然后我读到可以通过添加适当的选项来防止复制省略。
输出
clear && g++ -fno-elide-constructors moves.cpp && ./a.out
但是,是下面的:
default ctor (id 0)
param ctor (id 1)
param ctor (id 2)
x0 = x1 + x2;
operator+
param ctor (id 3)
move ctor (id 4)
dtor on id 3 (array of size 0: [])
move assignment ("moving" 5 values)
dtor on id 4 (array of size 0: [])
X x4(x1 + x2);
operator+
param ctor (id 5)
move ctor (id 6)
dtor on id 5 (array of size 0: [])
move ctor (id 7)
dtor on id 6 (array of size 0: [])
[0,0,3,4,0]
dtor on id 7 (array of size 5: [0,0,3,4,0])
dtor on id 2 (array of size 5: [0,0,0,4,0])
dtor on id 1 (array of size 5: [0,0,3,0,0])
dtor on id 0 (array of size 5: [0,0,3,4,0])
+enrico:CSGuild$
看起来我期望的对 move 构造函数的调用现在就在那里,但是那个调用和对 move 赋值的调用之前分别有另一个对 move 构造函数的调用。
为什么会这样?我是否完全误解了 move 语义的含义?
最佳答案
您在这里似乎有两个问题:
X x4(x1 + x2)
调用 move 构造函数? Isn't that situation (X x4(x1 + x2);) exactly the one for which move semantics where supposed to be introduced?
嗯,不。为了使用 move 语义,您有效地建议我们应该选择在 operator+
中构造一个 X
,然后 move 它到结果 x4
,这与在 operator+
。
禁用复制省略后,为什么我们在 X x4(x1 + x2)
期间看到对 move 构造函数的两次调用?考虑到这里有三个作用域:
operator+
作用域,我们在其中构造一个X
并返回它;X x4(x1 + x2)
的 main
作用域;X 构造函数
,我们从 x1 + x2
构造一个 X
;然后,在没有省略的情况下,编译器是:
operator+
move 到 main
(进入 x1 + x2
);和x1 + x2
的内容 move 到 x4
。关于c++ - move 构造函数和 move 赋值运算符与复制省略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56104100/
这是我在这里的第一篇文章,也是我第一次使用 C++。我正在查看从 Internet 获得的一些代码,但我对此有疑问。 它有一个 for 循环,像这样: for(cin >> t;t--;) 我明白它在
我目前正在开发一个网站,除其他外,该网站允许用户通过显示或隐藏他们已购买的商品来过滤市场。这适用于基本的 AJAX 调用,该调用传递可用过滤器的当前条件,然后使用 CodeIgniter 的事件记录构
我创建了一个 MWE,其中通过添加 来更改单行解决编译器错误。 以下代码无法编译: import java.util.List; public class MainClass { publi
当我想测试一些 PostgreSQL 函数 FOO() 的行为时,我发现执行类似 SELECT FOO(bar) 的查询很有用,bar一些数据我用作直接输入,而无需从真实表中SELECT。 我读到我们
在 PHP、Java、C++(以及许多其他语言)中,for 循环是这样使用的: for(int i=0;i<10;i++) 如果我已经初始化了i,我该如何省略初始化语句呢? 最佳答案 在 Java、C
我发现我们的 Android 应用出现了一个奇怪的问题,特别是在 4.4 版的 Moto X 上。 在偏好 Activity 中,所有标题的前 8 个字符都在开头用省略号截断。这也发生在溢出菜单和整个
我有一个 XElement,我必须解析它以删除结束标记中的空白。我的代码如下所示: var stringBuilder = new StringBuilder(); using (var string
假设我有两个接口(interface),X和 Y ,它们共享一些字段,但也有独立的字段: interface X { abc: number; foo: number; bar: numb
我有这个模型: var accountSchema = new mongoose.Schema({ 'seeker': { 'fullName': String,
我在 R 中运行一个具有大量时间和位置固定效应的回归。我尝试将一个漂亮的汇总表输出到 Latex 中。我从 stargazer 包切换到 huxtable,因为 stargazer 在忽略固定效果时表
假设我有一个数据框: a df a b c d 1 0 9 10 2 1 10 13 3 NA 11 14 4 3 NA 7 5 4 13 22 现在假设我
我在 R 中运行一个具有大量时间和位置固定效应的回归。我尝试将一个漂亮的汇总表输出到 Latex 中。我从 stargazer 包切换到 huxtable,因为 stargazer 在忽略固定效果时表
我想删除一个属性并返回一个新对象而不改变原始对象。 我知道我们可以像这样使用 Lodash 轻松做到这一点: const profile = { name: 'Maria', age: 30 } _.
我正在通过更改一些内容来修改 javascript 对象。当我重新创建它时,我会得到每个 key 对的索引号。 "0":{...},"1":{...}, 如何删除/省略这些 0、1、2、3、4 数字的
我正在一个非常方便且名称丰富的网站 here 上完成示例之一。 ,具体来说: func applyMutliplication(value: Int, multFunction: Int -> Int
这个问题在这里已经有了答案: Why do java source files require package declarations? (4 个答案) 关闭 6 年前。 我是 Java 的新手,
在下面的代码中: Widget makeWidget() { return Widget(); } void foo(Widget widget) { ... } foo(makeWid
这是我使用下面的调用调用的过程: CALL abc('01-04-2011','14-04-2014','28,29,36,37,38','33,34,35,41,42,43') 但问题是下面提到的查
嘿,我正在寻找一种在 yui 数据表中省略文本的好方法。我的意思是,格式化文本,使其很好地适合其单元格,并且如果文本必须被 chop ,则在其后面有一个椭圆 (...)。 我想在不使用 CSS 选择器
我有一个如下表(记录)。 ID Status AA124 Pass AA125 Pass Z_AA134 Fail Z_AA135
我是一名优秀的程序员,十分优秀!