【发布时间】:2018-05-18 23:00:01
【问题描述】:
我已经实现了一个自定义容器(与 std::vector 相同),并且我正在尝试制作它,以便它的“push_back”功能将利用移动语义来避免创建被推回的任何内容的副本 -特别是当要推入容器的对象由外部函数返回时。
在阅读了大量有关移动语义和自定义容器的内容后,我仍然无法找到为什么我的方法仍然生成副本而不是仅仅将传递的对象移动到容器的内部动态数组中。
这是我的容器的简化版本,如下所示:
template<class T>
class Constructor
{
private:
size_t size = 0;
size_t cap = 0;
T *data = nullptr;
public:
Constructor()
{
cap = 1;
size = 0;
data = static_cast<T*>(malloc(cap * sizeof(T)));
}
~Constructor()
{ delete[] data; }
template<typename U>
void push_back(U &&value)
{
if (size + 1 >= cap)
{
size_t new_cap = (cap * 2);
T* new_data = static_cast<T*>(malloc(new_cap * sizeof(T)));
memmove(new_data, data, (size) * sizeof(T));
for (size_t i = 0; i<cap; i++)
{
data[i].~T();
}
delete[] data;
cap = new_cap;
data = new_data;
new(data + size) T(std::forward<U>(value));
}
else
{
new(data + size) T(std::forward<U>(value));
}
++size;
}
const T& operator[](const size_t index) const //access [] overloading
{
return data[index];
}
};
这是一个自定义类,它会在创建、复制或移动其实例时打印消息,以帮助调试:
class MyClass
{
size_t id;
public:
MyClass(const size_t new_id)
{
id = new_id;
std::cout << "new instance with id " << id << std::endl;
}
MyClass(const MyClass &passedEntity)
{
id = passedEntity.id;
std::cout << "copied instance" << std::endl;
}
MyClass(MyClass &&passedEntity)
{
id = passedEntity.id;
std::cout << "moved instance" << std::endl;
}
void printID() const
{
std::cout << "this instance's id is " << id << std::endl;
}
};
这里是外部函数:
MyClass &foo(MyClass &passed)
{
return passed;
}
最后,这里是 main 函数,它使用上述函数和类运行测试用例来显示问题:
int main()
{
MyClass a(33);
std::cout << std::endl;
std::cout << "Using my custom container: " << std::endl;
Constructor<MyClass> myContainer;
myContainer.push_back(foo(a));
myContainer[0].printID();
std::cout << std::endl;
std::cout << "Using dinamic array: " << std::endl;
MyClass *dinArray = static_cast<MyClass*>(malloc(1 * sizeof(MyClass)));
dinArray = new(dinArray + 1) MyClass(std::forward<MyClass>(foo(a)));
dinArray[0].printID();
std::cout << std::endl;
system("Pause");
return 0;
}
输出是:
new instance with id 33
Using my custom container:
copied instance
this instance's id is 33
Using dinamic array:
moved instance
this instance's id is 33
可以看出,如果将MyClass 的实例直接放入动态数组中,那么只调用了移动构造函数而不是复制构造函数。但是,如果我将 yClass 实例 push_back 到 Container 的实例中,仍然会调用复制构造函数。
有人可以帮我理解我在这里到底做错了什么吗?我怎样才能使元素被推入容器而不生成副本?
【问题讨论】:
-
这就是 c++11 的
emplace_back()背后的基本原理。 -
如果您想在 C++03 中模拟移动语义,请使用 std::swap:
void emplace(vector<T>& v, T& value) { v.resize(v.size()+ 1); std::swap(v.back(), value); }您可能还必须为某些类型定义 std::swap。某种伪移动构造函数。
标签: c++11 copy containers move-semantics