我正在开发一个相当复杂的数学库,当客户端代码使用 auto 时,我发现了一个令人讨厌的错误。在创建一个最小的复制案例来提出一个问题的过程中,我意识到我可以单独使用标准库来复制类似的东西。查看这个简单的测试用例:
#include <vector>
#include <assert.h>
int main()
{
std::vector<bool> allTheData = {true, false, true};
auto boolValue = allTheData[1]; // This should be false - we just declared it.
assert(boolValue == false);
boolValue = !boolValue;
assert(boolValue == true);
assert(allTheData[1] == false); // Huh? But we never changed the source data! Only our local copy.
}
Run Code Online (Sandbox Code Playgroud)
住在 Godbolt 上。(有趣的事实:Clang 实际上将其优化为写入“7” - 3 个真位 - 以及对 __assert_fail 的调用。)
(是的,我知道 std::vector<bool> 很烂- 但在这种情况下,创建一个只有几行长的最小可重现示例很方便)这是一个较长的示例,它不使用 std::vector<bool>,并且使用自定义容器类型,删除了分配和复制/移动,仍然显示问题。
我了解幕后发生的事情,operator[] 返回的代理类旨在实现allTheData[1] …
可以将结构分配给另一个,这会导致将所有值从struct复制到另一个:
struct
{
int a, b, c;
} a, b;
...
a = b;
Run Code Online (Sandbox Code Playgroud)
但为什么数组不能像这样分配:
int a[3], b[3];
...
a = b;
Run Code Online (Sandbox Code Playgroud)
因为,严格来说,结构只是具有可变大小元素的数组,那么为什么不允许这样呢?无论如何,这种任务尚未使用.当然,似乎只涉及地址,但可以轻松地复制数组("静态").
我有一个用例,我的对象不得以任何方式复制.我在下面写了一个夸张的复制构造函数和复制赋值运算符删除的完整列表.有这么多,我无法确定使用哪些,有时这让我变得偏执.我不必在我的代码中全部写出来,是吗?因此,为了防止任何类型的对象复制,我应该使用哪些对象?
MyClass ( MyClass &) = delete;
MyClass (const MyClass &) = delete;
MyClass ( MyClass &&) = delete;
MyClass (const MyClass &&) = delete;
MyClass operator=( MyClass &) = delete;
MyClass operator=(const MyClass &) = delete;
const MyClass operator=( MyClass &) = delete;
const MyClass operator=(const MyClass &) = delete;
MyClass & operator=( MyClass &) = delete;
MyClass & operator=(const MyClass &) = delete;
const MyClass & operator=( MyClass &) = delete;
const MyClass & operator=(const MyClass &) = …Run Code Online (Sandbox Code Playgroud) c++ copy-constructor copy-assignment deleted-functions implicit-methods
这有什么区别:
TestClass t;
Run Code Online (Sandbox Code Playgroud)
还有这个:
TestClass t = TestClass();
Run Code Online (Sandbox Code Playgroud)
我希望第二个可能会调用构造函数两次然后调用operator =,而是调用构造函数一次,就像第一次一样.
我们foo是一个结构或类与拷贝赋值运算符:
struct foo {
foo &operator=(const foo &); // or with some other return type?
};
Run Code Online (Sandbox Code Playgroud)
是否有过一个合理的退货理由比其他任何东西*this从operator=()?将它用于与任务无关的事情并不合理.
说我想覆盖operator =所以我可以做类似的事情
Poly p1; // an object representing a polynomial
Poly p2; // another object of the same type
p2 = p1; // assigns all the contents of p1 to p2
Run Code Online (Sandbox Code Playgroud)
然后在我的实现中operator =,我有这样的事情:
Poly& Poly::operator=(const Poly &source) {
// Skipping implementation, it already works fine…
return *this;
}
Run Code Online (Sandbox Code Playgroud)
不介意实现,它已经正常工作.
我关心的是你什么时候会发生什么return *this?我知道它返回对象的引用,但这是怎么回事?
p2 = &p1
Run Code Online (Sandbox Code Playgroud) 我有一个类似于以下的类定义:
class UUID
{
public:
// Using implicit copy assignment operator
private:
unsigned char buffer[16];
};
Run Code Online (Sandbox Code Playgroud)
我刚刚对我进行了单元测试失败,验证了副本分配是否正常工作.令我惊讶的是,buffer []数组中间的一个字节被错误地复制了.
我的理解是,默认的复制赋值操作符执行成员复制,而数组成员(不是指向数组的成员)则需要执行元素的元素复制.我错了吗?
我在这里的直觉是,我被一个悬挂在指针中间的指针咬了一下.但是,当我将这些物体的矢量复制到另一个矢量时,我可以重复地看到这一点.
有人想告诉我哪里出错了吗?
编辑:
为了扩展这一点,该类不是POD类型 - 它派生自一些抽象基类,因此具有虚拟析构函数.但是,数组是唯一的数据成员,单元测试中的用法是这样的:
const int n = 100;
std::vector<UUID> src, dst;
src.reserve(n);
dst.resize(n);
for (int i = 0; i < n; ++i) {
UUID id;
src.push_back(id);
}
for (int i = 0; i < n; ++i) {
dst[i] = src[i];
}
bool good = true;
for (int i = 0; i < n; ++i) {
const bool thisGood …Run Code Online (Sandbox Code Playgroud) 我有以下非类型模板:
template<size_t MAX_SIZE>
struct Path{
struct Point{
float x;
float y;
}
};
Point segment[MAX_SIZE];
};
Run Code Online (Sandbox Code Playgroud)
如果我现在声明两个不同的路径,我不能将不同段的元素相互分配,因为结构可能具有相同的结构,但是具有不同的类型:
Path<10> path_a ;
Path<30> path_b ;
path_a.segment[0].x = 1;
path_a.segment[0].y = 2;
path_b.segment[0] = path_a.segment[0]; // <- error C2679 in Visual Studio)
Run Code Online (Sandbox Code Playgroud)
当然,如果我将Point和Path的定义分开,那么赋值将起作用:
struct Point{
float x;
float y;
};
template<size_t MAX_SIZE>
struct Path{
Point segment[MAX_SIZE];
};
Run Code Online (Sandbox Code Playgroud)
但这不是我想要的(这只是一个MWE),所以我想知道如何重载复制赋值运算符以使其工作.我尝试了很多变种,例如:
template<size_t MAX_SIZE>
struct Path{
struct Point{
float x;
float y;
template<size_t OTHER_SIZE>
Point & operator = (const typename Path<OTHER_SIZE>::Point & that)
{
x = that.x; …Run Code Online (Sandbox Code Playgroud) 当我读到有关复制构造函数和复制赋值构造函数的内容时,我理解的是两者都将它们的属性相互给出,并且它们都是由编译器隐式声明的(如果没有定义).因此,无论是否有用,都必须存在.
然后我测试了这段代码:
#include <iostream>
using namespace std;
class Test {
public:
Test () {
cout << "Default constructor" << endl;
}
Test (const Test& empty) {
cout << "Copy constructor" << endl;
}
Test& operator=(const Test& empty) {
cout << "Copy assignment operator" << endl;
}
private:
};
int main () {
Test a; // Test default constructor
Test b (a); // Test copy constructor
Test c = b; // Test copy assignment constructor
system ("pause");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但似乎根本没有调用复制赋值运算符.我尝试了三个条件: …
我想创建一个包含迭代器类的列表数据结构。一切正常,但是当我声明移动赋值运算符时,如果程序使用 C++14 或 C++11 标准,则该程序不会编译,但在 C++17、C++2a 中运行良好。
列表.h:
#pragma once
#include <iostream>
template <typename T>
class list {
struct node {
node(T data, node* prev = nullptr, node* next = nullptr)
: data{ data }, prev{ prev }, next{ next } {}
T data;
node* prev;
node* next;
};
public:
struct iterator {
template <typename>
friend class list;
explicit iterator(node *_node = nullptr)
: _node(_node) {}
iterator& operator=(iterator const &it) {
_node = it._node;
return *this;
}
iterator& operator=(iterator &&it) …Run Code Online (Sandbox Code Playgroud) c++ ×10
copy-assignment ×10
arrays ×2
struct ×2
c ×1
c++11 ×1
c++17 ×1
constructor ×1
non-type ×1
templates ×1