std ::对象效率列表

Jos*_*ain 5 c++ stl

假设你有一个类的std :: list.您可以通过两种方式制作此列表:1)

std::list<MyClass> myClassList;
MyClass myClass;
myClassList.push_front(myClass);
Run Code Online (Sandbox Code Playgroud)

使用此方法,将对象传递给列表时将调用复制构造函数.如果该类有许多成员变量,并且您多次进行此调用,则可能会变得昂贵.

2)

std::list<MyClass*> myClassList;
MyClass* myClass = new MyClass();
myClassList.push_front(myClass);
Run Code Online (Sandbox Code Playgroud)

此方法不会调用该类的复制构造函数.我不完全肯定在这种情况下会发生什么,但我认为该列表将创建一个新的MyClass*并分配参数的地址.事实上,如果你在堆栈而不是堆上创建myClass并让它超出范围,那么myClassList.front()是无效的,因此必须如此.

如果我错了,请反驳我,但我相信第二种方法对某些类来说效率更高.

Mat*_* M. 3

这始终是一个值得思考的问题。

首先,这实际上取决于您的编译器是否支持 C++11 移动语义,因为这会极大地改变问题的各个方面。

对于那些陷入 C++03 困境的人

有多种选择:

std::list<MyClass> list;
list.push_front(MyClass());
Run Code Online (Sandbox Code Playgroud)

即使在语义上存在副本,优化器也可能会删除大部分冗余/死存储。大多数优化器将要求默认构造函数和复制构造函数的定义可用。

boost::ptr_deque<MyClass> deque;
std::auto_ptr<MyClass> p(new MyClass());
deque.push_front(p);
Run Code Online (Sandbox Code Playgroud)

ptr_vectorpush_front如果你替换为就可以使用push_back,否则有点浪费。这避免了 a 的大部分内存开销,std::list<MyClass*>并且具有自动处理内存的额外好处。

boost::stable_vector<MyClass> svec;
svec.push_back(MyClass());
//        ~~~~
Run Code Online (Sandbox Code Playgroud)

有一个副本(与列表一样),但保证容器内不应再进行任何副本(与列表一样)。它还允许比列表更多的操作(例如,随机访问),但代价是在大型容器的中间插入速度较慢。

对于那些喜欢 C++11 的人

std::list<MyClass> list;
list.push_front(MyClass());
Run Code Online (Sandbox Code Playgroud)

不生成任何副本,而是发生移动操作。

还可以使用提供的新操作来就地构造对象:

std::list<MyClass> list;
list.emplace_front();
Run Code Online (Sandbox Code Playgroud)

MyClass会直接在节点内创建一个新的,没有复制,没有移动。

最后,您可能希望对容器进行更紧凑的表示或其他操作,在这种情况下:

std::vector<std::unique_ptr<MyClass>> vec;
vec.emplace_back(new MyClass());
Run Code Online (Sandbox Code Playgroud)

为您提供随机访问和较低的内存开销。