仅在Release中使用gcc编译时出现void操作符删除[](void*)错误

问题描述 投票:0回答:1

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_
变量获取它,它似乎是以相同的方式初始化和删除的。

我尝试更改删除功能,但我所做的一切都不起作用或导致编译时错误。

c++ delete-operator
1个回答
0
投票

rowm1_--
已经有未定义的行为。不允许在其指向的数组边界之外递增或递减指针(除了将其递增到对象之后)。

因此条件

rowm1_ ++;
if(rowm1_ != NULL )

没有意义。永远不可能通过递增指针来获得空指针。

我猜这会导致编译器的分析确定您必须在不是

delete[] rowm1_
结果的指针上调用
new[]
,因为唯一可行的方法是
rowm1_
已经指向递增之前的数组。因此,递增的指针不能位于分配的偏移量零处。

您使用

-Werror
在此警告中犯了致命错误,这就是它无法编译的原因。

即使您删除

-Werror
以使其编译,生成的程序也将具有未定义的行为,并且编译器不太可能对警告进行类似的推理以优化代码,这可能会产生非常意外的结果。

如果这个库到目前为止还可以运行,那么编译器没有进行任何有害的优化就很幸运了。

© www.soinside.com 2019 - 2024. All rights reserved.