我有一个模板化的类,它包装了一个名为mObjects的std :: vector。
Class有一个 insert 函数,它在MyArray实例中转发实际存储类型的参数(我认为它叫做variadic模板参数)。在这个例子中,我存储了MyMesh类型,但它可以是任何类型。
正如你在main()函数中看到的那样,mObjects向量不会增长,它的元素会被反复覆盖。
考虑一种对象池类型的数据结构。
一切都按预期工作。
template <class T>
class MyArray
{
public:
MyArray(const int capacity) :
mObjects(capacity)
{
mNextIndex = 0;
}
template <typename... Args>
void insert(Args&&... args)
{
mObjects[mNextIndex] = T{ std::forward<Args>(args)... }; //PROBLEMATIC ASSIGNMENT
//... not relevant code
}
private:
int mNextIndex;
std::vector<T> mObjects;
};
int main()
{
MyArray<Mesh> sa(2);
sa.insert("foo",1111); //goes to mObjects[0]
sa.insert("bar",2222); //goes to mObjects[1], and tada, the vector is full
sa.remove(1111); //not implemented above, but not relevant. Remove func basically adjusts mNextIndex, so mObjects[0] will be overwritten upon next insert.
sa.insert("xxx",3333); //mObjects[0] gets overwritten from "foo" to "xxx" and 1111 to 3333
}
我的问题是上面有一行被评为//问题分配。
mObjects[mNextIndex] = T{ std::forward<Args>(args)... };
当该命令执行时,会发生三件事:
调用MyMesh(const string s,int x)构造函数,这意味着整个MyMesh在堆栈上被分配。为什么?我只想将转发的参数传递给现有的mObjects [mNextIndex]元素。
operator =(MyMesh&amp;&amp; other)被调用,并通过临时变量和mObjects [mNextIndex]之间的变量进行赋值变量。
~cVMesh()被调用意味着临时变量释放并死亡。
我想摆脱#1和#3。所以不要想要“昂贵”的临时对象创建。我只想将传入的MyMesh参数转发/分配给mObjects [mNextIndex]。与std :: vector.emplace_back()的作用类似,但与mNextIndex指向的任何位置相同。
如何在不实例化临时变量的情况下,只将参数转发到C ++中的现有变量?
对于completness,这里是MyMesh类,它存储在MyArray类中。当调用构造函数/析构函数/分配运算符时,没有什么特别的只是打印出一些消息:
class Mesh
{
public:
Mesh()
{
cout << "Mesh()" << std::endl;
mStr = "";
mId = 99999999;
}
Mesh(const string s, int x)
{
cout << "Mesh(const string s, int x)" << std::endl;
mStr = s;
mId = x;
}
~Mesh()
{
cout << "~Mesh()" << std::endl;
}
Mesh& operator=(const Mesh& other)
{
cout << "operator=(const Mesh& other)" << std::endl;
cout << mStr << " becomes " << other.mStr << endl;
cout << mId << " becomes " << other.mId << endl;
mStr = other.mStr;
mId = other.mId;
return *this;
}
Mesh& operator=(Mesh&& other) noexcept
{
cout << "operator=(Mesh&& other)" << std::endl;
cout << mStr << " becomes " << other.mStr << endl;
cout << mId << " becomes " << other.mId << endl;
mStr = other.mStr;
mId = other.mId;
return *this;
}
Mesh(const Mesh& other)
{
cout << "Mesh(const Mesh& other)" << std::endl;
mStr = other.mStr;
mId= other.mId;
}
Mesh(Mesh&& other) noexcept
{
cout << "Mesh(Mesh&& other)" << std::endl;
mStr = other.mStr;
mId = other.mId;
other.mStr = "";
other.mId = 99999999;
}
string mStr;
int mId;
};
答案 0 :(得分:3)
我认为你想要的是用新值重建向量中的任意元素
#include<vector>
template<class T, class... Args>
void create_at_nth_place(std::vector<T>& v, int n, Args&&...args){
auto& elem = v[n];
elem.~T();
new(&elem) T(std::forward<Args>(args)...);
}
struct S {
S();
S(int, bool);
template<class... Args>
S(Args&&...);
S(S&&) noexcept;
~S();
};
void f() {
std::vector<S> v(3);
create_at_nth_place(v, 2, 4323, false);
char a = 'a';
create_at_nth_place(v, 2, 'a', 123, 1232, 32.f, a);
}
答案 1 :(得分:1)
mObjects[mNextIndex] = T{ std::forward<Args>(args)... };
行创建一个临时对象,对已存储在指定位置的向量中的对象执行移动(复制)分配,最后销毁临时对象。
整个MyArray
类没有用,因为vector
已经具有类似的功能。
vector<Mesh> sa;
sa.reserve(2);
sa.emplace_back("foo",1111); // Mesh constructor called once
sa.emplace_back("bar",2222); // Mesh constructor called once again
答案 2 :(得分:1)
您可以添加:
void assign(const string& s, int x)
{
cout << "assign(const string s, int x)" << std::endl;
mStr = s;
mId = x;
}
并使用它:
mObjects[mNextIndex].assign(std::forward<Args>(args)...);
答案 3 :(得分:1)
如果你的网格类很重,你应该考虑使用指针数组,这样可以完全消除虚假副本。不会MyArray<std::shared_ptr<MyMesh>>
按原样工作吗?