我和我的 C++ 同事遇到了一个奇怪的结构:
struct A { int i; };
void foo(A const& a);
int main() {
foo(A() = A{2}); // Legal
}
Run Code Online (Sandbox Code Playgroud)
这个A() = A{2}表达式完全把我们弄糊涂了,因为它似乎正在分配A{2}给一个临时的、默认构造的对象。但是在编译器资源管理器中看到它(https://gcc.godbolt.org/z/2LsfSk)。它似乎是一个法律声明(由 GCC 9 和 Clang 9 支持),如下声明:
struct A { int i; };
int main() {
A() = A{2};
auto a = A() = A{3};
}
Run Code Online (Sandbox Code Playgroud)
因此,在某些情况下,它似乎A()是一个左值。还是这里发生了其他事情?希望得到一些解释,最好是对 C++17 标准的引用。
更新:@Brian 发现这是赋值给右值的重复:为什么编译?. 但如果有人能在 C++ 标准中找到合适的参考,我将不胜感激。
如果我有一个数组作为成员的类:
class A
{
Object array[SIZE];
};
Run Code Online (Sandbox Code Playgroud)
我复制了它的一个实例:
A a;
A b = a;
A c;
c = a;
Run Code Online (Sandbox Code Playgroud)
将array逐字节地进行memcpy-ed还是Object::operator=逐个元素复制?
我了解在什么情况下会调用哪个...
Sample a;
Sample b = a; //calls copy constructor
Sample c;
c = a; //calls assignment operator
Run Code Online (Sandbox Code Playgroud)
我的问题是,为什么这两种不同的东西都存在?为什么只有两者之一不能同时解决这两种情况?
例如,我的一本书中的代码如下:
class HasPtr {
public:
HasPtr(const HasPtr& h): ps(new std::string(*h.ps)), i(h.i) { }
HasPtr(const std::string &s = std::string()): ps(new std::string(s)), i(0) { }
HasPtr& operator=(const HasPtr&);
~HasPtr() { delete ps; }
private:
std::string *ps;
int i;
};
HasPtr& HasPtr::operator=(const HasPtr &rhs){
auto newp = new string(*rhs.ps); // copy the underlying string
delete ps; // free the old memory
ps = newp; // copy data from rhs into this object
i = rhs.i;
return *this; // return this object
}
Run Code Online (Sandbox Code Playgroud)
看起来像运营商的内部=可能只是: …
在这里,您可以看到自我分配检查的复制赋值运算符实现:
String & operator=(const String & s)
{
if (this != &s)
{
String(s).swap(*this); //Copy-constructor and non-throwing swap
}
// Old resources are released with the destruction of the temporary above
return *this;
}
Run Code Online (Sandbox Code Playgroud)
这对于自我分配很有用,但对性能有害:
所以,我还是不明白,如果我想实现std::vector的operator=我将如何实现它.
我发现一些线程严重意味着无法完成,但没有一个使用完全相同的运算符和条件组合,所以我想更具体地问.希望这意味着对某人来说这是一个快速而简单的答案......无论如何!
考虑一个示例代理类,用于管理较大存储块中的值 - 如此过于简化但有代表性的示例:
class SomeProxyThing {
std::uint32_t storage;
public:
operator std::uint16_t() const
{
return storage & 0x0000FFFF;
}
SomeProxyThing &operator=(std::uint16_t const value)
{
storage &= 0xFFFF0000;
storage |= value;
}
};
Run Code Online (Sandbox Code Playgroud)
我想通过用户定义的s 来完成所有作业operator.在这种情况下,用户应该只能传入或取出"暴露"类型std::uint16_t.我可能正在使用各种代理类类型,并希望它适用于所有这些类型.理想情况下,对于任何类型的组合,我只需键入someProxy = anotherProxy并让编译器完成其余的工作.
但是,当赋值的左侧和右侧具有相同或继承相关的类型时,默认的复制赋值运算符 - 当然 - 与此目标冲突.它复制了整个storage,从而破坏了另一半uint32_t- 而不是根据需要只复制'暴露'值.这是正确的!对于大多数情况.但即使LHS和RHS类型相同,我也想要一种"通过转换分配"的方法.为了避免这种情况,我可以:
operators 执行'代理'副本- 这是我一直在做的,但它似乎有点hacky,并且像任何用户定义的构造函数/赋值运算符一样,打破了平凡的可复制状态对的struct-我需要保持.它仍然memcpy()s ^ 反正在g++,但我想定义的行为.= delete复制赋值运算符(我们现在可以为TC类型执行).但是,赋值仍然会尝试使用它并抛出编译错误 - …我的课A显式实现了它的复制构造函数和复制赋值。
当复制分配此类元素的向量时,使用哪种复制机制?
这是:
vector<A> a1, a2(5);
a1 = a2;
Run Code Online (Sandbox Code Playgroud)
是否要对A的所有新元素使用 的复制构造函数a1,并将 的元素a2作为输入?
a1或者它会为元素腾出空间,然后使用A'operator=和 的 元素a2作为输入?
a1如果赋值前不为空怎么办?
还指定了吗?
我的类的复制构造函数并operator=没有完全执行相同的操作(这是不好的做法吗?到目前为止主要是测试内容)。看起来复制构造函数被调用了,但我想知道是否一定会这样,或者在这种情况下是否恰好如此。
Qt定义Q_DISABLE_COPY如下:
#define Q_DISABLE_COPY(Class) \
Class(const Class &) = delete;\
Class &operator=(const Class &) = delete;
Run Code Online (Sandbox Code Playgroud)
Q_DISABLE_COPY是在使用QObject类,但它的文件说,它应该在其所有的子类可以作为很好:
当你创建自己的子类的QObject(董事或间接的),你应该不给它一个拷贝构造函数或赋值操作符。然而,简单地从类中省略它们可能还不够,因为如果您错误地编写了一些需要复制构造函数或赋值运算符的代码(这很容易做到),您的编译器会为您精心创建。你必须做得更多。
但是考虑这个程序:
struct Base {
Base() = default;
private:
Base(const Base &) = delete;
Base &operator=(const Base &) = delete;
};
struct Derived : Base {};
int main() {
Derived d1;
Derived d2(d1); // error: call to implicitly-deleted copy constructor of 'Derived'
Derived d3;
d3 = d1; // error: object …Run Code Online (Sandbox Code Playgroud) c++ derived-class copy-constructor copy-assignment deleted-functions
我正在设计一个类,它应该有一个名为K. 我也希望这个类有一个复制赋值运算符,但编译器似乎从任何具有 const 数据成员的类中隐式删除了复制赋值运算符。这段代码说明了基本问题:
class A
{
private:
const int K;
public:
A(int k) : K(k) {} // constructor
A() = delete; // delete default constructor, since we have to set K at initialization
A & operator=(A const & in) { K = in.K; } // copy assignment operator that generates the error below
}
Run Code Online (Sandbox Code Playgroud)
这是它生成的错误:
constructor.cpp:13:35: error: cannot assign to non-static data member 'K' with const-
qualified type 'const int'
A & operator=(A const & in) { …Run Code Online (Sandbox Code Playgroud) 在 C++ 中,存在臭名昭著的自赋值问题:在实现 时operator=(const T &other),必须小心,this == &other不要this在从 复制数据之前破坏 的数据other。
然而,*this和other可能以比作为同一个对象更有趣的方式交互。即,一个可以包含另一个。考虑以下代码:
#include <iostream>
#include <string>
#include <utility>
#include <vector>
struct Foo {
std::string s = "hello world very long string";
std::vector<Foo> children;
};
int main() {
std::vector<Foo> f(4);
f[0].children.resize(2);
f = f[0].children; // (1)
// auto tmp = f[0].children; f = std::move(tmp); // (2)
std::cout << f.size() << "\n";
}
Run Code Online (Sandbox Code Playgroud)
我希望行(1)和(2)是相同的:程序被明确定义为 print 2。然而,我还没有找到一个编译器+标准库组合,可以与启用的行 …
c++ assignment-operator language-lawyer copy-assignment memory-aliasing