std::move在堆栈变量上使用有意义吗?

4

我需要创建一个大小为1024的结构体列表。因此,我尝试通过利用移动语义来优化列表的推操作。但是根据我的知识,移动语义只对堆分配的内存有意义。请问有人能建议更好的方法吗?这是我的代码:

#include <iostream>
#include <list>
    
struct St {
    int32_t arr[1024];
};
    
int main() {
    std::list<St> struct_list;
    for(int32_t i = 0; i < 1024; ++i) {
        St st; // stack allocated and memory gets deallocated after each loop
        std::cout << &st << std::endl;
        struct_list.emplace_back(std::move(st)); // I feel std::move doesn't make any sense here even if I implement move constructor, still data gets copied into the std::list which is allocated in heap, so not efficient.
        std::cout << &struct_list.back() << "\n" << std::endl;
    }
        
    return EXIT_SUCCESS;
}

你觉得它为什么不应该呢? - πάντα ῥεῖ
1
"但是移动语义只对堆分配的内存有意义"。您能告诉我这句话的出处吗? - πάντα ῥεῖ
2个回答

6

假设您当前定义了 St:

struct St {
    int32_t arr[1024];
};

从技术角度来说,对于St的这个特定定义,移动和拷贝都会得到相同的结果。

然而,从语义上讲,标记st为移动操作是有意义的,因为你已经用完了它,而且st最终也会被销毁。例如,如果后来你决定将St的定义更改为以下内容:

struct St {
    std::vector<int32_t> vec;
};

那么它将产生差异 - 矢量数据成员将被移动而不是复制。

简而言之,我的建议是专注于移动操作的语义 - 即对象是否应该被移动。如果你无论如何都要处理这个对象,那么很可能会。


2
如果您能升级到C++17,您可以使用emplace_back的返回值,以便首先将其添加到列表中,然后再填充它。您可以(如果默认构造,就像您的示例一样)首先emplace_back一个新实例,然后使用.back()获取它并填充它。
堆栈分配和释放对于POD而言并不昂贵。重要的是您对其执行的逻辑。
关于移动,对于这个例子,std::move将与复制相同,因此不需要它。但是,如果这是一个std::string数组,std::move将允许您将字符串从一个数组移动到另一个数组。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接