我有一个类,其成员是向量的向量.我想为这个类编写一个构造函数,它将一个向量的r值引用作为参数,并将其作为vector参数的单个元素向量移动到成员向量中.到目前为止,我有:
class AClass
{
std::vector<std::vector<int>> member;
public:
AClass(std::vector<int> &&vec) : member(1)
{
member[0] = std::vector<int>(std::move(vec));
}
}
Run Code Online (Sandbox Code Playgroud)
这似乎工作正常,但我不确定std::move周围vec是否有必要.或者,如果std::vector我已经为我照顾了很多这个,那我的写法有点不同.
我想创建一个工厂样式生成器,它接收A并输出A,RA的子类(它向A添加信息).我不能想到一个安全的方法来做到这一点.
结构体:
class A
{
public:
std::string str;
A(std::string a)
{
str = a;
}
A(A&& a) :
str(std::move(a.str))
{
}
};
class AR : public A
{
public:
std::string str1;
AR(std::string a,std::string b) : A(a)
{
str1 = b;
}
AR(A &&a,const std::string& b)
: A(std::forward<A>(a))
{
str1 = b;
}
AR(AR&& ar)
: A(std::forward<A>(ar)),
str1(std::move(ar.str1))
{
}
};
class ARFactory;
Run Code Online (Sandbox Code Playgroud)
最安全的方式可能是
AR GenerateRA1(A&& a)
{
return AR(std::forward<A>(a),std::string("foo"));
}
Run Code Online (Sandbox Code Playgroud)
这将强制a被破坏.问题是,这会导致用户在函数调用之前无法以任何方式使用a的参数,这可能很烦人:
ARFactory fact;
{
AR ar=fact.GenerateRA1(A("bar"));//compiles
}
{
A a("bar"); …Run Code Online (Sandbox Code Playgroud) 我正在玩Move Semantics和[r | l]值引用来学习如何在真实世界的程序中使用它们.考虑以下代码:
// Item is a heavy class having move ctor and assignment but no copy.
std::map<std::string, Item*> lookup;
std::forward_list<Item> items;
void FooClass::addItem(Item&& d) {
if (lookup.find(d.getName()) == lookup.end()) {
lookup[d.getName()] = &d; //<== not safe after move?
items.push_front(std::move(d));
}
}
Run Code Online (Sandbox Code Playgroud)
我正在获取一个地址Item&&并将其存储在指针中.然后将数据移动到std::forward_list(items).我假设调用移动赋值不会影响对象的地址.那是对的吗?虽然d移动后内容不再有效.这是查找表(lookup)的内容不正确.
我假设我必须重新订购a)添加查找项目和b)移动实际数据.上面的代码并不理智.它是否正确?
我也不明白为什么我要说std::move那里.编译器应该知道这d是一个右值引用.所以它应该调用std::forward_list<T>::push_front(T&&)并移动赋值...
也就是说,当一个人利用C++ 11 typename &&功能(如移动构造函数等)时,通常会在设计良好的C++ 03代码中获得多少性能提升?多长时间值得麻烦,在什么情况下?
编辑:
想象一个替代的宇宙,而不是右值引用C++ 11使用关键字"returns"扩展C++ 03,该关键字标记将由函数返回的局部变量.如果局部变量被标记为"返回",则将其放置在堆栈中通常存在返回值的部分中.想象一下,您可以像这样使用该关键字:
SomeClass foo()
{
returning SomeClass bar; // Created where return value usually resides.
// do something with bar
return bar; // No copy constructor is involved here.
}
Run Code Online (Sandbox Code Playgroud)
我认为这样的机制可以创建make_unique,就像右值引用一样,并且可以减少混淆和潜在的陷阱.三法则仍然是三法则而不是成为五法则; 没有混淆是否&& if rvalue ref或universal ref; 没有必要std :: move等.
我在这里错过了什么?
示例程序:
#include <iostream>
#include <string>
#include <vector>
template <typename T>
void print(const T& _vec)
{
for( auto c: _vec )
std::cout << c << ",";
}
typedef std::vector<std::string> vecstr_t;
struct Trade
{
explicit Trade(vecstr_t&& vec) : _vec(vec )
{
}
vecstr_t _vec;
};
int main()
{
vecstr_t tmpV = {"ONE", "TWO", "THREE", "FOUR"};
std::cout << "size 1:" << tmpV.size() << "\t"; print(tmpV); std::cout << "\n" ;
Trade t(std::move(tmpV));
std::cout << "size 2:" << tmpV.size() << "\t"; print(tmpV); std::cout << "\n" …Run Code Online (Sandbox Code Playgroud) 如果所有类(如果有的话)通过move ctor创建类的实例,与复制ctor相比,如果所述类的成员主要是像int这样的基本类型,那么这些成员是不是像副本一样复制的那些成员构造函数?那么什么时候移动提供更好的性能,在处理自定义类时?
MyType同时定义了副本和移动ctor.执行以下代码段时(使用VS2015编译后):
template<typename T>
void f(T&& o) {
// do something with o
}
int main() {
MyType o{ 1, 2, 3 };
f(o); // call of copy-constructor expected
f(std::move(o)); // call of move-constructor expected
}
Run Code Online (Sandbox Code Playgroud)
我希望f在第二次调用之后第一次调用和移动构造函数之后调用复制构造函数f.但是在任何情况下都没有构造函数被调用.我怀疑这种行为是编译器优化,但我不确定可移植性或符合标准.
考虑以下代码:
class A {
private:
std::string data;
public:
void set_data(std::string&& data) {
this->data = std::move(data); // line 6
}
};
int main() {
std::string move_me = "Some string";
A a;
a.set_data(std::move(move_me)); // line 13
}
Run Code Online (Sandbox Code Playgroud)
我知道我们需要调用std::move()第13行,以便它向左值引用转换左值(这听起来是否正确?我是新手).
但是,在第6行,我们需要std::move()再次使用吗?我假设没有,因为我们已经传递了一个右值引用,并且std::string将调用移动构造函数.那是对的吗?
我有一个非常简单的示例类,使用C ++ 17编译。
#include <string>
#include <iostream>
struct name {
std::string first, middle, last;
name() = default;
name(name const&) = default;
name(name &&) = default;
name& operator=(name o) {
std::swap(*this, o); // bad!
return *this;
}
};
int main() {
name n1{"mr", "john", "smith"};
name n2 = std::move(n1);
name n3 = n2;
std::cout << n3.first << " " << n3.middle << " " << n3.last;
}
Run Code Online (Sandbox Code Playgroud)
使用这种价值语义,将移动分配捆绑在一起,我故意将其称为合格交换,而不是using std::swap; swap(*this, o);。无论如何,我没有提供交换。考虑到STL将交换实现为移动构造和一系列移动分配,因此我认为此实现将无限递归,交换调用move和移动调用swap。被std::swap改变成成员明智的掉期或类似的东西?
我正在努力使自己了解移动语义。我很困惑,因为我找不到为什么我们需要它,以及如何理想地使用它。
例如,当我们通过std :: move移动对象时,它将使对象变为nullptr。为什么会这样?另外,为什么std :: move将对象变成右值?这是怎么发生的?为什么在将std :: move与变量一起使用后,它没有用null填充,但是当我将其与vector之类的对象一起使用时,将其移动后,便用nullptr填充了它。
我希望有人逐步解释CPP的移动语义和其他语义。我读得越多,我就越困惑。它是CPP编程中最复杂的主题之一。