为什么在 c++ 中隐式删除了 const-members 的赋值运算符?[复制]

Why Assignment Operator implicitly deleted for const-members in c++? [duplicate]

提问人:JoeVictor 提问时间:3/25/2023 最后编辑:JoeVictor 更新时间:3/28/2023 访问量:887

问:

这与关闭请求所附的问题不是重复的。

我有一个具有 const 限定字段的类。我正在尝试将其分配给在我分配的位置已经具有值的数据结构。但是因为我的类有一个 ,我的编译器不允许我这样做。const-qualified field


错误:

根据编译器的不同,我得到:

note: copy assignment operator of 'A' is implicitly deleted because field 'size' is of const-qualified type 'const unsigned short'

艺术

error: non-static const member ‘const short unsigned int A::size’, cannot use default assignment operator

这基本上是一回事。


最小可行示例:

#include <iostream>
#include <vector>
class A {
    private:
        const unsigned short size;
     
    public:
    
        A(unsigned short sz) : size(sz) {}
        
        void print_sz() {
            std::cout<<this->size<<"\n";
        }
};

int main()
{
    A a = A(2);
    
    std::vector<A> a_vec = std::vector<A>();
    a_vec.push_back(A(0));
    a_vec[0] = A(1); // This line breaks my code
    
    a_vec[0].print_sz(); // I want to see 1 printed here
    return 0;
}

这对我来说没有意义......为什么它不能隐式复制常量值?

谁在乎它是不是 const,只是复制一下该死的短篇!

我试过还有很多其他的事情std::move

我不想实现复制赋值运算符并手动复制每个成员,因为在我的实际代码中有太多字段和动态数组,我知道如果我尝试实现它,我会搞砸一些东西。

我只想把一个放到我的向量中......A


问题:

1 - 如何解决此问题?我想要任何有效的快速黑客,并且不需要实现复制分配运算符。我不关心容器中已有的元素。我只想将数据从临时堆栈移动到向量中(在其他地方使用)

2 - 如果你有时间,我很想解释为什么这是有道理的......


谢谢。

c++ 编译器错误 复制赋值

评论

1赞 user12002570 3/25/2023
分配将被删除,因为默认情况下,它只复制/分配给类的每个数据成员。但是由于变量不能赋值,因此没有必要使用赋值运算符(应该进行赋值)。operator=const
1赞 PaulMcKenzie 3/25/2023
我不在乎容器中已有的元素——忘记了这一点,赋值运算符的目的是一回事,而且只是一件事——将一个对象赋值给另一个对象,仅此而已。一旦将“业务逻辑”放入赋值运算符中,就有可能创建实际上不是副本的副本。这为你打开了最难追踪的错误之一,那就是应该相等的对象不相等。请记住,编译器还将调用赋值运算符,而不仅仅是由您显式调用。const
2赞 The Dreams Wind 3/25/2023
根据经验,避免使用成员变量的修饰符,因为它们的恒度应由所属对象的恒度管理const
0赞 PaulMcKenzie 3/25/2023
如果你需要做一个“奇怪”的作业,就写一个函数。不要用于此。同样,使用基本赋值运算符来具有会产生副作用的逻辑将以眼泪告终。此外,您的示例甚至不需要向量:assign()operator=A a(2); A anotherA(3); a = anotherA;

答:

2赞 user12002570 3/25/2023 #1

分配将被删除,因为默认情况下,它只分配给类的每个成员。但是,由于变量不能赋值,因此使用隐式赋值运算符是没有意义的。这既适用于复制分配,也适用于移动分配。operator=const

评论

0赞 JoeVictor 3/25/2023
如何告诉编译器:“将临时变量的所有内容移动到”?a_vec[0]
1赞 user12002570 3/25/2023
@JoeVictor 你不能!由于此处也不能使用移动分配运算符。尝试更改 const 变量是未定义的行为。只是不要试图改变常量变量。
2赞 Jerry Coffin 3/25/2023 #2

你不能在这里做作业。您已指定 是 ,这意味着您可以初始化它,但不能分配给它。sizeconst

一种(丑陋的)解决方法是销毁现有对象,然后使用新位置在同一位置创建具有新值的新对象。

#include <iostream>
#include <vector>
class A {
    private:
        const unsigned short size;
     
    public:
    
        A(unsigned short sz) : size(sz) {}
        
        void print_sz() {
            std::cout<<this->size<<"\n";
        }
};

int main()
{
    A a = A(2);
    
    std::vector<A> a_vec = std::vector<A>();
    a_vec.push_back(A(0));
    a_vec[0].~A();        // out with the old
    new (&a_vec[0]) A(1); // and in with the new
    
    a_vec[0].print_sz(); // Prints `1`
    return 0;
}

评论

0赞 JoeVictor 3/25/2023
我喜欢这个答案。但有一个问题:你在这里的电话引入了内存泄漏,对吧?或者矢量容器是否在其析构函数中管理新分配的内存?new
1赞 Jerry Coffin 3/25/2023
@JoeVictor:不,放置不会分配任何内存,它只是在指定位置构造一个对象。new
0赞 JoeVictor 3/25/2023
了不起。我学到了一些新东西我解决了我的问题。谢谢!
2赞 john 3/25/2023
在 C++20 中,我们有 std::construct_at 这是做同样事情的一种稍微更明显的方式。还有来自C++17。std::destroy_at
0赞 JoeVictor 3/25/2023
棒。谢谢,然后需要考虑从 C++14 升级!