为什么创建initializer_list会导致副本?

时间:2017-07-19 11:15:51

标签: c++ c++11 initializer-list

在SO中有几个问题(like this)关于无法将对象移出初始化列表以及如何导致过多的副本。这个问题

我的问题是,鉴于初始化列表基本上是支持浅拷贝的本地有效const引用的容器,为什么它会在创建时导致其(左值)元素的副本?初始化列表中的Rvalues不会被复制,只是被移动,但是lvalues确实被复制了。这是一个显示它的例子:

#include <initializer_list>
#include <iostream>
#include <vector>

struct A
{
    A()
    {
        std::cout << "Creating A" << std::endl;
    }

    ~A()
    {
        std::cout << "Deleting A" << std::endl;
    }

    A(const A &other)
    {
        std::cout << "Copying A" << std::endl;
    }

    A(A &&other)
    {
        std::cout << "Moving A" << std::endl;
    }

    A &operator=(const A &other)
    {
        std::cout << "Copy-assigning A" << std::endl;
        return *this;
    }

    A &operator=(A &&other)
    {
        std::cout << "Move-assigning A" << std::endl;
        return *this;
    }
};

int main(int, char **)
{
    A a;
    std::cout << "Creating initializer list 1." << std::endl;
    std::initializer_list<A> il1 { a };
    std::cout << "Created initializer list 1." << std::endl;
    std::vector<A> v {A(), A(), A()};
    std::cout << "Creating initializer list 2." << std::endl;
    std::initializer_list<std::vector<A>> il2 { v };
    std::cout << "Created initializer list 2." << std::endl;
    return 0;
}

输出(使用GCC 5.4和Clang 3.8):

Creating A
Creating initializer list 1.
Copying A
Created initializer list 1.
Creating A
Creating A
Creating A
Copying A
Copying A
Copying A
Deleting A
Deleting A
Deleting A
Creating initializer list 2.
Copying A
Copying A
Copying A
Created initializer list 2.
Deleting A
Deleting A
Deleting A
Deleting A
Deleting A
Deleting A
Deleting A
Deleting A

相关部分是Creating...Created...之间的部分,可以看出初始化列表生成其参数的副本。查看cppreference,它表示(作为C ++ 14规范的一部分)std::initializer_list<T>在内部保存一个数组const T[N],这将解释副本。我不明白为什么这是必要的。正如评论中所建议的,解决方法是使用指针初始化器列表或std::reference_wrapper s,但如果内部结构本身是一个指针数组或std::reference_wrapper s,则不会更好。 ?就像现在一样,看起来好像初始化程序列表与rvalues(或轻型对象)一起使用,但同时它们不允许将对象移出它们。是否存在将左值复制到内部结构可能有害的情况?或者只是为了避免一个指针取消引用操作?

0 个答案:

没有答案