使用std::vector的emplace与const引用成员

huangapple go评论72阅读模式
英文:

Using std::vector's emplace with const reference member

问题

我之前在一个具有类A的向量上使用emplace_back,该类具有类Handle的const引用成员变量,并且一切都正常。但是我需要将其更改为使用emplace,以便能够在特定索引处插入。但是似乎编译不通过。查看cppreference时,我无法确定这两种方法之间的区别,除了其中一种需要显式迭代器。

我在使用emplace时遇到错误:

In file included from main.cpp:7:
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/vector:1759:18: error: object of type 'A' cannot be assigned because its copy assignment operator is implicitly deleted
            *__p = _VSTD::move(__tmp.get());
                 ^
main.cpp:41:6: note: in instantiation of function template specialization 'std::vector<A>::emplace<int, double, Handle &&>' requested here
        foo.emplace(foo.begin() + 3, 3, 4.5, h);
            ^
main.cpp:22:16: note: copy assignment operator of 'A' is implicitly deleted because field 'h_' is of reference type 'const Handle &'
        const Handle& h_;

我是否需要更改我的类设计以适应使用emplace

我找到了这个问题链接,但似乎没有提供替代方案。

英文:

I was using emplace_back on a vector of my class A that has a const reference member variable of class Handle with some success. However I needed to change it to use emplace instead to be able to insert at certain index. But that doesn't seem to compile. Looking at cppreference, I can't tell what the difference between the two methods is, except that one takes an explicit iterator

#include &lt;vector&gt;

class Handle
{
	int do_something();
};

class A
{
public:
	A(int a, float d, const Handle&amp; h) : a_(a), d_(d), h_(h) {}
private:
	int a_;
	float d_;
	const Handle&amp; h_;
};

int main()
{
	Handle h;
	std::vector&lt;A&gt; foo;
    foo.reserve(10);
	foo.emplace_back(3, 4.5, h); // OK
    // foo.emplace(foo.begin() + 3, 3, 4.5, h); // NOT OK
}

I get an error on using emplace :

In file included from main.cpp:7:
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/vector:1759:18: error: object of type &#39;A&#39; cannot be assigned because its copy assignment operator is implicitly deleted
            *__p = _VSTD::move(__tmp.get());
                 ^
main.cpp:41:6: note: in instantiation of function template specialization &#39;std::vector&lt;A&gt;::emplace&lt;int, double, Handle &amp;&gt;&#39; requested here
        foo.emplace(foo.begin() + 3, 3, 4.5, h);
            ^
main.cpp:22:16: note: copy assignment operator of &#39;A&#39; is implicitly deleted because field &#39;h_&#39; is of reference type &#39;const Handle &amp;&#39;
        const Handle&amp; h_;

Do I need to change my class design to accommodate using emplace?

I found this question but it doesn't seem to provide an alternative

答案1

得分: 1

你的代码正在尝试将元素插入到空的std::vector中的非末尾位置,这是不允许的。std::vector::emplace方法在指定的位置插入一个元素,但该位置必须在容器的范围内(即在begin()和end()之间)。

在你的代码中,位置foo.begin() + 3 超出了当前foo的范围。你可以按照以下方式修改你的代码:
使用emplace_back方法而不是emplace方法,它将新元素附加到std::vector的末尾。

foo.emplace_back(3, 4.5, h);

或者,在使用emplace方法之前使用resize方法增加std::vector的大小。

foo.resize(10);
foo.emplace(foo.begin() + 3, 3, 4.5, h);

但要注意,上述代码将在foo的前三个位置创建具有默认构造的A对象。如果A类没有默认构造函数,或者您不希望创建这些默认对象,您可能需要寻找其他解决方案。

此外,A类包含对Handle类的常量引用,这会导致A类的复制构造函数和复制赋值运算符被删除。这是因为引用成员一旦初始化就不能更改其引用的对象。如果std::vector需要在内部移动或复制元素(例如,当容器需要调整其内部存储大小时),它将需要使用这些已删除的复制构造函数或复制赋值运算符,从而导致编译错误。您可能需要修改A类的设计,使其可以复制或移动。

英文:

Your code is attempting to insert an element into a non-end position in an empty std::vector, which is not allowed. The std::vector::emplace method inserts an element at the specified position, but that position must be within the range of the container (i.e., between begin() and end()).

In your code, the position foo.begin() + 3 is out of range for the current foo.
You can modify your code in the following ways:
Use the emplace_back method instead of the emplace method, which will append the new element to the end of the std::vector.

foo.emplace_back(3, 4.5, h);

Or, increase the size of the std::vector using the resize method before using the emplace method.

foo.resize(10);
foo.emplace(foo.begin() + 3, 3, 4.5, h);

However, beware that the above code will create A objects with default construction at the first three positions of foo. If the A class does not have a default constructor, or if you do not want to create these default objects, you might need to seek other solutions.

Moreover, the A class contains a constant reference to the Handle class, which causes the copy constructor and copy assignment operator of the A class to be deleted. This is because a reference member cannot change the object it refers to once it has been initialized. If std::vector needs to move or copy elements internally (for example, when the container needs to adjust its internal storage size), it will need to use these deleted copy constructors or copy assignment operators, leading to a compile error. You may need to modify the design of the A class to make it copyable or movable.

huangapple
  • 本文由 发表于 2023年7月14日 09:25:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/76684168.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定