首页 > 解决方案 > 有没有办法将分配的对象实际移动到 std::list

问题描述

在 C 风格的链表中,您只需设置指向已分配对象的指针,而在 C++ 中,复制似乎是不可避免的。
天真的测试代码:

#include <cstring>
#include <iostream>
#include <chrono>
#include <memory>
#include <list>
#include <vector>
using std::cout;

struct LinkedS{
    LinkedS *next = nullptr;
    float f;
    std::vector<float> v{1};
};

struct S{
    float f;
    std::vector<float> v{1};
};

int main()
{
    S* s = new S;
    cout << &s->v.front() << ' ' << &s->f << '\n';
    std::list<S> li;
    li.push_front( std::move( *s ) );
    cout << &li.front().v.front() << ' ' << &li.front().f << '\n';
}

https://godbolt.org/z/33T4179Gj
这里vector内容实际上是移动的,但不幸的是struct数据还是被复制了。

标签: c++c++17

解决方案


的这种用法new不是一个好的 C++,它不是 Java/C#,new除非你必须,否则不要使用,当你必须时,使用std::unique_ptr.

你在找emplace_frontemplace_back?他们可以在其最终目的地构造存储的对象。

C++20

#include <list>
#include <vector>
struct S{
    float f;
    std::vector<float> v;

};

int main()
{
    std::list<S> li;
    li.emplace_front(42.4f,std::vector{1.f,2.f,3.f,4.f,5.f});
    
}

C++17

遗憾的是,在 C++20 之前,需要一个构造函数,聚合不计算在内。

#include <list>
#include <vector>

struct S{
    float f;
    std::vector<float> v;
    S(float f, std::vector<float> v):f(f),v(std::move(v)){}
};

int main()
{
    std::list<S> li;
    li.emplace_front(42.4f,std::vector{1.f,2.f,3.f,4.f,5.f});
    
}

如果您确实需要将预分配的指针传递给容器,那是不可能的。本身std::list不是链表,它仅对可能导致链表实现的操作有要求。此外,所有 STL 容器都使用可定制的分配器,并且每个分配器都拥有并为其容器提供存储,它不能从外部源传入。

尽管最近出现了一些带有节点std::map::extractstd::map::insert在节点上运行的关联容器的例外情况。理论上,std::list将来可能也会得到它们。

真正的链表

没有什么能阻止你创造std::list<std::unique_ptr<T>>和使用它。


推荐阅读