C++-带有指针的Weffc++警告
C++ -Weffc++ warning with pointers
我很难理解这个错误。我正在使用-Weffc++
标志进行编译。
这个结构编译得很好。
struct A
{
A(){}
int * first = nullptr;
int second = 0;
};
这不是在编译。
struct B
{
B(){}
int * first = nullptr;
std::vector<int> second{};
};
我得到:
prog.cc:14:8: warning: 'struct B' has pointer data members [-Weffc++]
14 | struct B
| ^
prog.cc:14:8: warning: but does not override 'B(const B&)' [-Weffc++]
prog.cc:14:8: warning: or 'operator=(const B&)' [-Weffc++]
但这又很好。
struct C
{
int * first;
std::vector<int>& second;
};
为什么我们会得到关于指针的错误(它们在每个结构中)?为什么添加std::vector<int>
会引发错误?我使用了最新的gcc 9.00
和C++2a
这是一个警告,而不是错误。在拥有默认构造函数的情况下,有些指针往往无法正确使用。如果希望警告消失,请定义构造函数和赋值运算符。三/五/零规则
struct B {
int* first;
std::vector<int> second;
B() : first(nullptr), second{} {} // default
B(const B&) = delete; // copy ctor
B(B&&) = delete; // move ctor
B& operator=(const B&) = delete; // copy assignment
B& operator=(B&&) = delete; // move assignment
~B() { delete[] first; } // dtor
};
如果不这样做,移动和复制类的实例可能会导致默认实例化构造函数/赋值运算符产生不必要的影响,例如复制/移动无法复制/移动的资源。看看析构函数,想想如果让默认方法处理指针会发生什么。
使用B
,编译器可以检测到可能违反"三条规则",并发出有效C警告。从Ted Lyngmo对这个问题的回答开始,许多其他地方都很好地解决了这个问题。
但为什么其他两个不触发相同的警告?
C
允许我们消除一半的顾虑:引用成员变量不能重新赋值,这会阻止编译器生成默认赋值运算符,从而造成任何损失。
C c; // uninitialized second. GCC misses this
C d;
c = d; //fails. deleted assignment operator
但是复制构造函数应该仍然是可能的并且是潜在的威胁。
C c; // uninitialized second. GCC misses this
C d(c); // but it does catch the uninitialized second if you do this
对C
的改进
std::vector<int> dummy;
struct C
{
C() :second(dummy) // initialize second
{
}
int * first = nullptr;
std::vector<int>& second;
};
允许
C c;
C d(c);
在没有有效C++警告的情况下编译,就像A
一样。我很长一段时间都无法理解这件事。这就提出了一个重要的问题。警告是由实施者提供的。如果有些事情很难或不可能证明,那就没有任何警告。
但为什么这个警告很严厉?
编译器必须知道如何查找潜在的问题。这意味着它将寻找问题的签名。这意味着一个或多个成员可能需要特殊处理、析构函数、复制构造函数或赋值运算符,而不需要"三规则"要求的其他两个特殊成员函数中的至少一个。
我怀疑GCC在发现至少一个特殊成员函数而不是全部时触发了有效C++警告。
让我们来看看这三个类的析构函数。A
的int
不需要特殊的销毁逻辑。C
的引用也没有。B
的vector
则是另一回事。至少它需要释放一些存储空间。这需要编译器生成一些代码,一旦有一个不做任何事情的析构函数,编译器就可以看到该类有一个析构函数而没有三规则的其他两个部分,并且包含可能需要特殊处理的成员(指针)。
所以
struct C
{
C() :second(dummy)
{
}
~C() // force a destructor
{
}
int * first = nullptr;
std::vector<int>& second;
};
应该并且确实提出有效的C++警告。
注意:生成的完全琐碎的复制构造函数
C c;
C d(c);
这本身似乎并没有引起警告。也没有提供复制构造函数。警告的钩子可能只在析构函数上,导致返回关于仅在Implementor的宽限期内存在的警告的警告。
- 警告处理为错误这里有什么问题
- 使用动态分配的数组会导致代码分析发出虚假的C6386缓冲区溢出警告
- cppcheck在const std::string[]上引发警告
- GCC对可能有效的代码抛出init list生存期警告
- 如何在BST的这个简单递归实现中消除警告
- 关于std::move的使用,是否有编译警告
- g++ 在某个类成员未初始化时不发出警告
- 如何处理来自核心指南检查器的关于gsl::at的静态分析警告
- 使用typeid警告未使用的变量
- 示例C++项目编译中的警告
- 警告:在函数返回类型 [-Wignore 限定符] 时忽略类型限定符
- 如何修复编译器警告 C6386 和 C6385?
- 返回语句后的代码,没有警告
- 获取隐式转换溢出从无符号到已签名的警告
- 编译器警告:执行到达值返回函数的末尾而不返回值
- 在未链接的部分上生成警告
- 警告 C4552:">>":未使用表达式的结果
- 返回 *这会给出 Weffc++ 警告
- C++-带有指针的Weffc++警告
- -Weffc++ 关于具有shared_ptr的简单结构的警告