STL 映射值构造函数

发布于 2024-09-24 19:51:56 字数 455 浏览 0 评论 0原文

我有一个类 X,我想将其放入 std::map 类型的 STL 映射中。 STL 映射需要将 X 存储在内存中的某个位置,因此我正在寻找一种有效的(运行时和内存)方法来创建 X 并将其存储在映射中。

我注意到以下代码,其中 x 是 X 类型的对象,而 stlMap 是 std::map 类型的映射:

stlMap["test"] = x;

导致调用以下内容:

  1. X 默认构造函数
  2. X 复制构造函数
  3. X 复制构造函数
  4. X
  5. 析构函数X 析构
  6. 函数 X 赋值构造函数
  7. X析构函数

为什么要创建这么多 X 对象?

这是对时间和内存的低效利用吗?

有没有更好的方法将对象放入地图中?也许将映射更改为字符串到 x* 的映射?

I have a class X that I would like to put into an STL map of type std::map. An STL map needs to have X stored in memory somewhere so I'm looking for an efficient (run time and memory) way to create X and store it in the map.

I noticed that the following code where x is an object of type X and stlMap is a map of type std::map:

stlMap["test"] = x;

Results in the following being called:

  1. X default constructor
  2. X Copy constructor
  3. X Copy constructor
  4. X destructor
  5. X destructor
  6. X assignment constructor
  7. X destructor

Why are so many X objects being created?

Is it an inefficient use of time and memory?

Is there a better way to put an object into a map? Maybe changing the map to be a map of strings to x*?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

長街聽風 2024-10-01 19:51:56

尝试 stlMap.insert( map::value_type("test", x) )

#include <iostream>
#include <string>
#include <map>

using namespace std;

class X
{
public:
X() { cout << "X default constructor" << endl; }
~X() { cout << "X destructor" << endl; }
X( const X& other ) { cout << "X copy constructor" << endl; }
X& operator=( const X& other ) { cout << "X copy-assignment operator" << endl; }
int x;
};


int main()
{
X x;
map< string, X > stlMap;

cout << "INSERT BEGIN" << endl;
stlMap.insert( map< string, X >::value_type( "test", x ) );
cout << "INSERT END" << endl;
stlMap.clear();
cout << "ASSIGN BEGIN" << endl;
stlMap["test"] = x;
cout << "ASSIGN END" << endl;

return 0;
}

在我的 g++ 上,将事情缩减为:

  1. X 复制构造函数
  2. X 复制构造函数
  3. X

析构函数 编辑:Per ArunSaha的建议,更新了测试。 insert() 输出不变,而赋值顺序如下所示:

  1. X 默认构造函数
  2. X 复制构造函数
  3. X 复制构造函数
  4. X 析构
  5. 函数 X 析构函数 X复制
  6. 赋值运算符

Try stlMap.insert( map<string, X>::value_type("test", x) ):

#include <iostream>
#include <string>
#include <map>

using namespace std;

class X
{
public:
X() { cout << "X default constructor" << endl; }
~X() { cout << "X destructor" << endl; }
X( const X& other ) { cout << "X copy constructor" << endl; }
X& operator=( const X& other ) { cout << "X copy-assignment operator" << endl; }
int x;
};


int main()
{
X x;
map< string, X > stlMap;

cout << "INSERT BEGIN" << endl;
stlMap.insert( map< string, X >::value_type( "test", x ) );
cout << "INSERT END" << endl;
stlMap.clear();
cout << "ASSIGN BEGIN" << endl;
stlMap["test"] = x;
cout << "ASSIGN END" << endl;

return 0;
}

On my g++ that whittles things down to:

  1. X copy constructor
  2. X copy constructor
  3. X destructor

EDIT: Per ArunSaha's suggestion, updated the test. The insert() output is unchanged, while the assignment sequence looks like this:

  1. X default constructor
  2. X copy constructor
  3. X copy constructor
  4. X destructor
  5. X destructor
  6. X copy-assignment operator
﹉夏雨初晴づ 2024-10-01 19:51:56

STL 容器具有复制语义,因此您观察到的情况是典型的。

您可以改用指针,但可以通过使用智能指针来避免相关的内存管理痛苦(以少量开销为代价)。

STL containers have copy semantics, so what you observe is typical.

You could use pointers instead, but you can avoid the associated memory-management pain by using smart pointers (at the cost of a small amount of overhead).

柒七 2024-10-01 19:51:56

以此作为参考:

#include <iostream>
#include <map>

class X
{
    public:
     X()                    { std::cout << "Default Construct\n";}
    ~X()                    { std::cout << "Destroy\n";}
     X(X const&)            { std::cout << "Copy Construct\n";}
     X& operator=(X const&) { std::cout << "Assignment\n";}
};


int main()
{
    std::map<int,X>     store;
    X                   x;
    X                   y;

    std::cout << "Inserting x\n";
    store[1]    = x;
    std::cout << "Finished Insert\n";
    std::cout << "Inserting y\n";
    store[1]    = y;
    std::cout << "Finished Insert\n";
}

运行我们得到以下输出:

Default Construct                    Building X
Default Construct                    Building Y
Inserting x                          ---- Start of an insert
Default Construct                    -------- Work to insert an item that is not in the map
Copy Construct                        
Copy Construct                       
Destroy                              
Destroy                             -------- Finished work to insert a new item
Assignment                          Assign x into the internal object
Finished Insert                     ---- Done
Inserting y                         ---- Start of an insert
Assignment                          Assign y onto the internal object.
Finished Insert                     ---- Done
Destroy                             Destroy y
Destroy                             Destroy x
Destroy                             Destroy map containing one X

Using this as a reference:

#include <iostream>
#include <map>

class X
{
    public:
     X()                    { std::cout << "Default Construct\n";}
    ~X()                    { std::cout << "Destroy\n";}
     X(X const&)            { std::cout << "Copy Construct\n";}
     X& operator=(X const&) { std::cout << "Assignment\n";}
};


int main()
{
    std::map<int,X>     store;
    X                   x;
    X                   y;

    std::cout << "Inserting x\n";
    store[1]    = x;
    std::cout << "Finished Insert\n";
    std::cout << "Inserting y\n";
    store[1]    = y;
    std::cout << "Finished Insert\n";
}

Running we get the following output:

Default Construct                    Building X
Default Construct                    Building Y
Inserting x                          ---- Start of an insert
Default Construct                    -------- Work to insert an item that is not in the map
Copy Construct                        
Copy Construct                       
Destroy                              
Destroy                             -------- Finished work to insert a new item
Assignment                          Assign x into the internal object
Finished Insert                     ---- Done
Inserting y                         ---- Start of an insert
Assignment                          Assign y onto the internal object.
Finished Insert                     ---- Done
Destroy                             Destroy y
Destroy                             Destroy x
Destroy                             Destroy map containing one X
感情旳空白 2024-10-01 19:51:56

STL 在复制和分配的基础上工作。因此,预计会有一定量的复制和分配。关于为什么这么多的问题,找到这个问题的一种方法是在 X 代码中的适当位置放置断点,然后在调试器中运行程序。

目前,std::map 正在为 X 进行内存管理。如果您切换到使用X*,那么您必须自己进行内存管理。我发现前者适合大多数情况。

STL works on the basis of copying and assigning. So some amount of copying and assignment is expected. On the question of why so many, one way to find that is to put breakpoints at appropriate positions in X code, and run the program in debugger.

In the current way, std::map is doing the memory management for X. If you switch to using X*, then you have to do the memory management yourself. I find the former suitable in most cases.

誰ツ都不明白 2024-10-01 19:51:56

启用优化后,构建和销毁的顺序是否不同?许多编译器在优化时可以省略此类语句中涉及的临时对象。我猜想优化后输出会涉及更少的对象。

C++0x 通过移动构造函数大大改善了这种情况。如果您的类 X 有一个移动构造函数(看起来像 X x(X&& m) { ... },那么您可以将语句更改为 stlMap["test" ] = std::move(x); 该语句本质上相当于构造一个 X,然后将其移至映射的所有权(如果您愿意)。没搞懂,都是有用的东西。

Is the order of construction and destruction different when you enable optimizations? Many compilers can omit temporary objects involved in such statements when optimizing. I'd guess the output would involve fewer objects when optimized.

C++0x improves the situation considerably with move constructors. If your class X has a move constructor (which will look like X x(X&& m) { ... }, then you can change your statement to stlMap["test"] = std::move(x);. That statement is essentially equivalent to constructing a single X and then moving it to ownership of the map. Look up some articles on C++0x move semantics if you're not clued up, it's useful stuff.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文