gcc (Ubuntu 12.3.0-1ubuntu1~23.04) 12.3.0 编译器警告标志 = -Wall;-Werror CMAKE_CXX_STANDARD_REQUIRED = 开
我正在使用一个库(TNT 的旧版本),它通过以下方式实现一些线性代数功能:
class Matrix
{
public:
typedef Subscript size_type;
typedef T value_type;
typedef T element_type;
typedef T* pointer;
typedef T* iterator;
typedef T& reference;
typedef const T* const_iterator;
typedef const T& const_reference;
Subscript lbound() const { return 1;}
protected:
Subscript m_;
Subscript n_;
Subscript mn_; // total size
T* v_;
T** row_;
T* vm1_ ; // these point to the same data, but are 1-based
T** rowm1_;
// internal helper function to create the array
// of row pointers
void initialize(Subscript M, Subscript N)
{
mn_ = M*N;
m_ = M;
n_ = N;
v_ = new T[mn_];
row_ = new T*[M];
rowm1_ = new T*[M];
assert(v_ != NULL);
assert(row_ != NULL);
assert(rowm1_ != NULL);
T* p = v_;
vm1_ = v_ - 1;
for (Subscript i=0; i<M; i++)
{
row_[i] = p;
rowm1_[i] = p-1;
p += N ;
}
rowm1_ -- ; // compensate for 1-based offset
}
...
析构函数以函数形式实现,如下:
void destroy()
{
/* do nothing, if no memory has been previously allocated */
if(v_ == NULL) return ;
/* if we are here, then matrix was previously allocated */
if(v_ != NULL) delete [] (v_);
if(row_ != NULL) delete [] (row_);
/* return rowm1_ back to original value */
rowm1_ ++;
if(rowm1_ != NULL )
delete[] rowm1_;
}
编译调试时,没有错误或警告。但是,我在编译 Release 时遇到错误。
具体来说,这会导致编译时错误:
error: ‘void operator delete [](void*)’ called on pointer ‘*(TNT::Matrix<double>*)((char*)this + 48).TNT::Matrix<double>::rowm1_’ with nonzero offset 8 [-Werror=free-nonheap-object]
192 | delete[] rowm1_;
| ^~~~~~~~~~~~~~~
C++ 标准版本号似乎并不重要(即 11/14/17)。
此外,我在调试或发布模式下都没有收到来自 MSVC 2019 的任何警告或错误。
我不明白为什么会出现此错误。
另外,我只为
rowm1_
变量获取它,而不为 row_
变量获取它,它似乎是以相同的方式初始化和删除的。
我尝试更改删除功能,但我所做的一切都不起作用或导致编译时错误。
rowm1_--
已经有未定义的行为。不允许在其指向的数组边界之外递增或递减指针(除了将其递增到对象之后)。
因此条件
rowm1_ ++;
if(rowm1_ != NULL )
没有意义。永远不可能通过递增指针来获得空指针。
我猜这会导致编译器的分析确定您必须在不是
delete[] rowm1_
结果的指针上调用 new[]
,因为唯一可行的方法是 rowm1_
已经指向递增之前的数组。因此,递增的指针不能位于分配的偏移量零处。
您使用
-Werror
在此警告中犯了致命错误,这就是它无法编译的原因。
即使您删除
-Werror
以使其编译,生成的程序也将具有未定义的行为,并且编译器不太可能对警告进行类似的推理以优化代码,这可能会产生非常意外的结果。
如果这个库到目前为止还可以运行,那么编译器没有进行任何有害的优化就很幸运了。