c++ - c ++ - 编译器忽略运算符新分配

  显示原文与译文双语对照的内容

我正在编写 C++ 中的512位整数。 对于整数,我使用 new 关键字从堆中分配内存,但是编译器( MINGW 上的G++ 版本 8.1 ) 似乎对它进行了wrongfully优化。 例如 编译器命令包括:

g++ -Wall -fexceptions -Og -g -fopenmp -std=c++14 -c main.cpp -o main.o

g++ -o binDebugcs.exe objDebugmain.o -O0 -lgomp

代码:


#include <iostream>


#include <cstdint>


#include <omp.h>



constexpr unsigned char arr_size = 16;


constexpr unsigned char arr_size_half = 8;


void exit(int);



struct uint512_t{


 uint32_t * bytes;


 uint512_t(uint32_t num){


//The line below is either (wrongfully) ignored or (wrongfully) optimized out


 bytes = new(std::nothrow) uint32_t[arr_size];


 if(!bytes){


 std::cerr <<"Error - not enough memory available.";


 exit(-1);


 }


 *bytes = num;


 for(uint32_t * ptr = bytes+1; ptr <ptr+16; ++ptr){


//OS throws error 0xC0000005 (accessing unallocated memory) here


 *ptr = 0;


 }


 }


 uint512_t inline operator &(uint512_t &b){


 uint32_t* itera = bytes;


 uint32_t* iterb = b.bytes;


 uint512_t ret(0);


 uint32_t* iterret = ret.bytes;


 for(char i = 0; i <arr_size; ++i){


 *(iterret++) = *(itera++) & *(iterb++);


 }


 return ret;


 }



 uint512_t inline operator =(uint512_t &b){


 uint32_t * itera=bytes, *iterb=b.bytes;


 for(char i = 0; i <arr_size; ++i){


 *(itera++) = *(iterb++);


 }


 return *this;


 }


 uint512_t inline operator + (uint512_t &b){


 uint32_t * itera = bytes;


 uint32_t * iterb = b.bytes;


 uint64_t res = 0;


 uint512_t ret(0);


 uint32_t *p2ret = ret.bytes;


 uint32_t *p2res = 1+(uint32_t*)&res;


//#pragma omp parallel for shared(p2ret, res, p2res, itera, iterb, ret) private(i, arr_size) schedule(auto)


 for(char i = 0; i <arr_size;++i){


 res = *p2res;


 res += *(itera++);


 res += *(iterb++);


 *(p2ret++) = (i<15)? res+*(p2res) : res;


 }


 return ret;


 }


 uint512_t inline operator += (uint512_t &b){


 uint32_t * itera = bytes;


 uint32_t * iterb = b.bytes;


 uint64_t res = 0;


 uint512_t ret(0);


 uint32_t *p2ret = ret.bytes;


 uint32_t *p2res = 1+(uint32_t*)&res;


//#pragma omp parallel for shared(p2ret, res, p2res, itera, iterb, ret) private(i, arr_size) schedule(auto)


 for(char i = 0; i <arr_size;++i){


 res = *p2res;


 res += *(itera++);


 res += *(iterb++);


 *(p2ret++) = (i<15)? res+(*p2res) : res;


 }


 (*this) = ret;


 return *this;


 }


//uint512_t inline operator * (uint512_t &b){


//}


 ~uint512_t(){


 delete[] bytes;


 }


};



int main(void){


 uint512_t a(3);


}



时间:

错误就在这一行,与 new的优化没有任何关系:


for(uint32_t * ptr = bytes+1; ptr <ptr+16; ++ptr){


//OS throws error 0xC0000005 (accessing unallocated memory) here


 *ptr = 0;


}



for的条件是错误的。 ptr <ptr+16 永远不会是 false 。 循环将永远继续,最终你将取消对无效内存位置的引用,因为 ptr 会不断增加。

另外,允许编译器执行优化,但不允许更改程序的外观行为。 如果代码执行 new,编译器可以优化它,如果它可以确保 new的副作用。

ptr <ptr+16 始终是 true,循环是无限的,最终会溢出它写入的缓冲区。

简单解决方案:值初始化 array,这样你就不需要循环:


bytes = new(std::nothrow) uint32_t[arr_size]();


//^^



如果复制一个实例,这个行为将被未定义,因为复制将指向同一个分配,两个实例都将。

简单解决方案:不要使用裸指针。 如果需要动态分配 array,请使用诸如 std::vector 之类的RAII容器。

注意:首先要考虑是否需要动态分配( 和相关的开销) 。 512位在许多情况下是相当安全的大小。

...