作为一个C++新手,我在理解C++ 11的新Move-Constructor时遇到了问题,我希望有人可以解释我偶然发现的具体情况.我们来看看这个示例代码:
#include <iostream>
using namespace std;
class Model {
public:
int data;
Model(int data) : data(data) { cout << "Constructor" << endl; }
Model(Model&& model) { cout << "Move constructor" << endl; }
~Model() { cout << "Destructor" << endl; }
private:
Model(const Model& model);
const Model& operator=(const Model&);
};
Model createModel(int data) {
return Model(data);
}
int main(void) {
Model model = createModel(1);
cout << model.data << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
所以我创建了一个createModel函数,它应该将模型作为临时右值返回,我想将它分配给左值.我不希望编译器创建Model对象的副本,因此我将复制构造函数定义为私有,并且我对赋值运算符执行相同操作以确保不复制任何数据.执行此操作后,代码正确不再编译,因此我添加了Move构造函数,现在它再次编译.但是当我运行程序时,我得到了这个输出:
Constructor
1 …Run Code Online (Sandbox Code Playgroud) 我有下课
class widget {
// The methods only print their name, i.e. c'tor, destructor etc.
public:
widget();
widget(const widget&);
widget(widget&&);
~widget();
auto operator=(const widget&) -> widget&;
auto operator=(widget&&) -> widget&;
};
Run Code Online (Sandbox Code Playgroud)
我在下面的代码中使用它
#include "widget.h"
auto main() -> int {
widget c(std::move(widget()));
c = std::move(widget());
return 0;
};
Run Code Online (Sandbox Code Playgroud)
由此产生的行为对我来说是可以理解的.在第一次调用中构造一个小部件,然后调用移动构造函数并在临时小部件上调用析构函数.
第二个调用也是这样,期望调用移动赋值运算符而不是移动构造函数.离开main方法,调用析构函数c.
现在有趣的是:
#include "widget.h"
auto main() -> int {
widget c((widget()));
c = widget();
return 0;
};
Run Code Online (Sandbox Code Playgroud)
如果我省略了调用std::move,第一个案例就会停止工作并导致只有一个构造函数调用.而第二个案件仍然像以前一样工作.
我在这里错过了什么?为什么这两个函数调用对待它们的参数有所不同?我在gcc和clang上尝试过这个.
考虑以下代码:
#include <iostream>
struct Test
{
int x;
int y;
};
Test func(const Test& in)
{
Test out;
out.x=in.y;
out.y=in.x;
return out;
}
int main()
{
Test test{1,2};
std::cout << "x: " << test.x << ", y: " << test.y << "\n";
test=func(test);
std::cout << "x: " << test.x << ", y: " << test.y << "\n";
}
Run Code Online (Sandbox Code Playgroud)
人们会期望这样的输出:
x: 1, y: 2
x: 2, y: 1
Run Code Online (Sandbox Code Playgroud)
这确实是我得到的.但由于复制省略,可能out在内存中的同一位置in并导致最后一行输出x: 2, y: 2?
我试着用gcc和铿锵既编译 …
测试环境:vs 2008,调试模式
测试代码是:
// a demo for return value
class C
{
public:
int value;
int value2;
int value3;
//C(int v=0): value(v) {};
};
C getC(int v)
{
C c1;
return c1;
}
int main()
{
C c1 = getC(10);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
而asm输出是:
; 39 : C c1 = getC(10);
push 10 ; 0000000aH
lea eax, DWORD PTR $T2595[ebp]
push eax
call ?getC@@YA?AVC@@H@Z ; getC
add esp, 8
mov ecx, DWORD PTR [eax]
mov DWORD PTR $T2594[ebp], ecx
mov …Run Code Online (Sandbox Code Playgroud) 我想让我清楚一下移动语义.我正在关注Bjarne Stroustrup第4版的例子,我真的输了.
他说当很多元素(在类向量中)所以移动语义是解决方案时,对象的副本可能很昂贵.
想想像:
矢量结果= vector1 + vector2 + vector3;
顺序可能是错误的,但它会(vector2 + vector3)生成部分结果result1,而result1 + vector1生成结果;
我重载了operator +:
Vector operator+(const Vector &a,const Vector &b)
{
if(a.size()!=b.size()) {
throw length_error{"Length of vectors must match for summing"};
}
Vector result(a.size());
cout << "Intermediate result for sum created" << endl;
for(long unsigned int i=0; i<result.size();i++){
result[i] = a[i] + b[i];
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
我还创建了一个移动构造函数:
Vector::Vector(Vector&& orig) noexcept
:elem{orig.elem},
sz{orig.sz}
{
cout << "Move constructor called" << endl;
orig.elem = nullptr; // We own …Run Code Online (Sandbox Code Playgroud) 我想尝试一下我读到的关于在C++中按值返回的内容(它与在新对象中创建时传递值相同)我有这样的代码:
#include <iostream>
using namespace std;
class Kar{
public:
int n;
static int no;
Kar(){
n = ++Kar::no;
cout << "Creating Kar " << n << endl;
}
Kar(Kar &k){
n = ++Kar::no;
cout << "Copying Kar " <<k.n<< " to new Kar " << n << endl;
}
~Kar(){
cout << "Destroying Kar "<< n << endl;
}
Kar& operator= (const Kar &k);
};
Kar& Kar::operator= (const Kar &k){
cout << "Assigning Kar "<< k.n <<" to Kar "<< …Run Code Online (Sandbox Code Playgroud) C++ 11引入了一个新的rvalue引用概念.我正在某处读它,发现如下:
class Base
{
public:
Base() //Default Ctor
Base(int t) //Parameterized Ctor
Base(const Base& b) //Copy Ctor
Base(Base&& b) //Move Ctor
};
void foo(Base b) //Function 1
{}
void foo(Base& b) //Function 2
{}
int main()
{
Base b(10);
foo(b); -- Line 1 (i know of ambiquity but lets ignore for understanding purpose)
foo(Base()); -- Line 2
foo(2) ; -- Line 3
}
Run Code Online (Sandbox Code Playgroud)
现在我的理解有限,我的观察结果如下:
第1行将简单地调用复制构造函数,因为参数是左值.
在C++ 11之前的第2行会调用复制构造函数和所有那些临时复制内容,但是定义了移动构造函数,这里将调用它.
第3行将再次调用move构造函数,因为2将隐式转换为Base类型(rvalue).
请纠正并解释上述任何观察结果是否错误.
现在,这是我的问题:
我知道一旦我们移动一个物体,它的数据就会在呼叫位置丢失.所以,我在上面的例子中如何更改第2行以在foo中移动对象"b"(是否使用std :: move(b)?).
我读过移动构造函数比复制构造函数更有效.怎么样?我只能想到在移动构造函数的情况下我们在堆上有内存的情况不需要再分配.当我们在堆上没有任何内存时,这个陈述是否成立?
它是否比通过引用传递更有效(不,对吧?)?
我正在阅读复制文章(以及它应该如何在C++ 17中得到保证),这让我有点困惑(我不确定我知道我以前认识的事情).所以这是一个最小的测试用例:
std::string nameof(int param)
{
switch (param)
{
case 1:
return "1"; // A
case 2:
return "2" // B
}
return std::string(); // C
}
Run Code Online (Sandbox Code Playgroud)
我看到它的方式,情况A和B对返回值执行直接构造,因此复制省略在这里没有意义,而案例C不能执行复制省略,因为有多个返回路径.这些假设是否正确?
另外,我想知道是否
std::string retval;总是返回一个或写入的情况下A,并B作为return string("1")等)"1"是暂时的,但我假设它被用作构造函数的参数std::stringreturn{},这会是一个更好的选择吗?)通过直接初始化传递临时对象来初始化对象时我有些困惑.
这是我想要了解的代码:
class Foo {
public:
Foo() { cout << "ctor()\n"; }
Foo(int) { cout << "ctor(int)\n"; }
Foo(const Foo&) { cout << "cpy-ctor\n"; }
Foo& operator=(const Foo&) { cout << "copy-assignment\n"; return *this; }
};
int main() {
Foo();// ctor (temporary object). it is not a function prototype because it requires a return type.
cout << endl;
Foo f; // ctor()
cout << endl;
Foo f2(Foo(7)); // ctor only once
cout << endl;
Foo f3(Foo(Foo(7))); // ctor(int), cpy-ctor() only …Run Code Online (Sandbox Code Playgroud) c++ ×10
c++11 ×4
compilation ×1
constructor ×1
copy-elision ×1
move ×1
oop ×1
protobuf-c ×1
stl ×1
vector ×1