2014-06-26 69 views
2

我研究过C++ 11移动语义,我有这样一个问题。C++ 11移动语义与C++ 98

例如:

如果我们有一个

vector<T> vt; // also assume that T have pointers on data in separate memory 
vt.push_back(...); 

承担vt缺乏未使用的容量。然后在C++ 98中,它将为每个T对象分配更多的内存并为它们指向的数据复制(调用构造函数副本)。

例如:

T1 - > T1数据=>将被复制t_cop1 - >(t1_cop1数据) T2 - > T2数据=> t_cop2 - >(t2_cop2数据)

C++ 11移动语义允许移动所有T对象(只需复制指针,但不要通过调用移动构造函数将数据复制到单独的内存中)。我们为什么不能在push_back中复制内存(其中包含指针t1,t2,因此t_cop1和t2_cop2将使用相同的指针创建),所以我们不能实现push_back,然后释放它(t1和t2使用free(void*)为例)?

UPD:好吧,我会尽量解释更简单的例子,我的问题:

举例来说,如果我们有一个包含一个指向某个数据结构数据的类。 我们实现一个拷贝构造函数是复制指针“数据”

class A { 
public: 
    A() {}; 
    A(const A& a) { 
     data = a.data; 
    } 
private: 
    struct Data{}; 
    Data* data; 
}; 

// And I want to implement "move semantics" by calling the copy constructor (that copies just pointer) 

A* a = new A(); 
A* b(a); 

// and then somehow free "a" object (but not call the destructor) 
free(a); // or a = NULL 

按照我的理解,这就是移动语义几乎做(但在某种一致的状态留下)。所以我认为我们实际上有能力在旧C++中实现移动。不是吗?

此外,我们可以做在前面的例子一样用向量

+0

我认为你误解了移动语义...... –

+0

这里没有区别C++ 11和C++ 98,因为移动指针时指针只是被复制。另外一个'vector '其中'T'是一个指针,只会围绕指针移动,而不会指向指针。 – nwp

+0

实际上,但C++ 98将调用深度复制,因此它不仅会复制指针,还会复制指针指向的所有数据。所以问题是为什么我们不能实现移动语义的C++ 98 – Nikita

回答

0

“移动语义”提供编译器将像构造函数的东西,可以分化为左值引用引用的方式(你的那种”在C++ 98中找到)和右值引用(新增C++ 11,使用&&表示法,它们指的是临时和中间对象,并且可能不会超过当前语句)。

所以,现在我们可以编写一个拷贝构造函数(“使新对象成为这个拷贝的副本”)和一个不同的移动构造函数(“使新对象成为这个拷贝的一个副本,并且通过源对象是一个临时的,将在下一个被销毁,所以如果你想以不会离开源对象完整的方式进行优化,请继续“)。因此,例如,在容器类中,可以使用复制构造函数复制容器类,并且新副本将包含其所有内容的完整副本(这意味着像元素一样的复制构造内容将会发生)。但移动构造函数可以跳过所有这些工作,只需将内部元素与源容器交换即可,只需接管源容器的内容并将源容器留空即可。 (后来源容器被破坏,这应该是微不足道的,因为它是空的。)通常可以在恒定的时间内完成,而不是O(N)或更糟。

在C++ 98中,您不能使用等效的作为构造函数(并因此使用临时对象),因为它只知道如何创建副本。有一种方法可以通过swap()函数(和某些类中的方法)实现类似的效果,但必须明确写入。 (基本上,容器a的内容移动到新构建的空容器b,可调用swap(a, b);,然后破坏a然后这将是空的。)的情况下的


一个例子,你只可以”吨做正确的事在C++ 98初始化向量与函数的返回一个向量的结果:

vector<int> fibonacci(int n) { 
    vector<int> result; 
    if(n <= 0) return result; 
    result.push_back(0); 
    if(n <= 1) return result; 
    result.push_back(1); 
    for(int i = 1; i < n; ++i) 
     result.push_back(result[i] + result[i - 1]); 
    return result; 
} 

vector<int> datavect = fibonacci(10); 

C++ 98和C++ 11都将远离的Elid函数返回复制(在存储返回值的位置创建result)但C++ 98可以o因为没有移动语义,所以只能调用datavect的拷贝构造函数。 C++ 11可以调用移动构造函数,它可以将存储从临时返回值移动到datavect。没有真正的方法来在C++ 98中执行此操作,而不涉及operator newoperator delete,并且返回指针而不是对象,从而在(非确定性时间)免费存储区上跳动以获得增益。

+0

是的,这就是移动语义所做的。所以我的问题是如何(或为什么不)我们不能在C++ 98中实现移动语义? – Nikita

+0

看我的最后一段。简而言之:你必须手动完成,而且在某些情况下不能完成它,比如返回容器的函数(而不是指针或引用)。 –

+0

是的,我同意在交换和斐波纳契旧C++的情况下是不合适的。但在我的例子中(并且也有向量),可以通过模拟移动语义来提高性能。那么为什么他们没有在C++ 11之前的stl中实现呢? – Nikita