如何在向量中构造一些类?

How to construct some classes in a vector?

提问人:Milad Rasouli 提问时间:8/16/2022 最后编辑:Milad Rasouli 更新时间:8/16/2022 访问量:68

问:

我正在处理一个类,我需要有类的向量。我希望将对象构建到位,而不是使用复制构建。似乎使用复制结构是不可避免的。

#include <iostream>
#include <string>
#include <vector>


class MyData {

public:
    int age;
    std::string name;

    MyData(int age, std::string name) : age(age), name(name)
    {
        std::cout << "MyData::MyData(int, std::string)\n";
    }

    MyData(const MyData& myData) : age(myData.age), name(myData.name)
    {
        std::cout << "MyData::MyData(const MyData&)\n";
    }

    MyData(MyData&& myData)
        :age(std::move(myData.age)), name(std::move(myData.name))
    {
        std::cout << "MyData::MyData(MyData&&)\n";
    }

    ~MyData() {
        std::cout << "MyData::~MyData()\n";
    }

};

#define DEBUG(...) std::cout << "Exec: " #__VA_ARGS__ << ";\n"; __VA_ARGS__ 

int main()
{

    DEBUG(std::vector<MyData> sb1);
    DEBUG(sb1.emplace_back(MyData{ 32, "SJ" }));
    DEBUG(sb1.emplace_back(MyData{ 42, "SJ" }));
}

代码输出如下:

Exec: std::vector<MyData> sb1;
Exec: sb1.emplace_back(MyData{ 32, "SJ" });
MyData::MyData(int, std::string)
MyData::MyData(MyData&&)
MyData::~MyData()
Exec: sb1.emplace_back(MyData{ 42, "SJ" });
MyData::MyData(int, std::string)
MyData::MyData(MyData&&)
MyData::MyData(const MyData&)
MyData::~MyData()
MyData::~MyData()
MyData::~MyData()
MyData::~MyData()

C:\Users\XOXOX\source\repos\cpp_stack\x64\Debug\cpp_stack.exe (process 12832) exited with code 0.
Press any key to close this window . . .

我正在使用 C++ 2020 和 MSVC。

C++ 矢量 容器 std

评论

0赞 Yksisarvinen 8/16/2022
sb1.emplace_back(32, "SJ").您的版本等效于 。push_back
0赞 Milad Rasouli 8/16/2022
感谢您的回复。但它仍然不起作用。
0赞 463035818_is_not_an_ai 8/16/2022
此处按预期工作:godbolt.org/z/EzYW13d3j。您仍然看到的一个副本是由于矢量调整大小和重新分配

答:

2赞 463035818_is_not_an_ai 8/16/2022 #1

你误解了什么。emplace_back

它接受您传递的参数,并将它们转发给相应的构造函数。

如果你这样做

sb1.emplace_back(MyData{ 32, "SJ" });

然后调用移动(或复制)构造函数。 不能神奇地撤消临时的创造。如果要就地创建元素,请不要传递临时的:emplace_backMyData

sb1.emplace_back(32, "SJ" );

这将使用 and 参数调用构造函数。intstd::string

评论

0赞 Milad Rasouli 8/16/2022
谢谢。它变得更好了。但它在调用 copy constructor 后仍然调用析构函数。这不是我需要的。我想在向量中构造类,而不会产生进一步的开销。我目前的结果是:''' Exec: std::vector<MyData> sb1;执行: sb1.emplace_back(32, “SJ” );MyData::MyData(int, std::string) exec: sb1.emplace_back(42, “SJ” );MyData::MyData(int, std::string) MyData::MyData(const MyData&) MyData::~MyData() MyData::~MyData() MyData::~MyData()'''
0赞 Sneftel 8/16/2022
@MiladRasouli 事实并非如此。至少,该代码没有。如果导致复制构造函数在刚刚构造的元素上调用(而不是在调整大小时调用以前的元素),那么您应该问一个新问题,因为这不是 C++ 所做的。emplace_back(your, args)
0赞 463035818_is_not_an_ai 8/16/2022
@MiladRasouli为什么它不是你需要的?被销毁的附加副本和元素来自矢量调整大小。您可以通过预先请求足够的容量来避免它,但不能通过单独在呼叫中执行某些操作来避免它emplace
0赞 Milad Rasouli 8/16/2022
我最近遇到了一个例子,和 .在示例中,这些用于地图。有趣的是,地图在 之后不会破坏类。现在我想做同样的事情,但为了std::piecewise_constructstd::forward_as_tupleemplacevector
1赞 463035818_is_not_an_ai 8/16/2022
@MiladRsouli这样做是一样的,只是向量在增加其容量时需要重新分配,地图没有容量。施工后尝试,重新分配将消失sb1.reserve(2)
6赞 Goswin von Brederlow 8/16/2022 #2

首先,当你写的时候

DEBUG(sb1.emplace_back(MyData{ 32, "SJ" }));

创建一个传递给函数的临时对象。关键是它调用了 costructor in-place。因此,您必须为它提供创建对象的参数,而不是临时对象,否则它必须使用复制/移动构造函数。emplaced_backemplace_back

第二个是容量为 0 的向量。因此,向其添加项目将不得不调整大小,这意味着复制,因为移动构造函数不是 . 无法在调整大小期间处理异常,因此它不会冒险使用移动构造函数。sb1noexceptstd::vector

您应该保留右侧以避免调整大小。

评论

0赞 Milad Rasouli 8/16/2022
谢谢。@463035818_is_not_a_number我之前需要打电话sb.reserve(2)emplace(...)
1赞 463035818_is_not_an_ai 8/16/2022
吹毛求疵:保留并不能避免调整大小。它避免了由于在向量调整大小时增加容量而重新分配。
0赞 Goswin von Brederlow 8/16/2022
我说的是支持向量的内存大小调整。不变。std::vector::size()