C++ New/Delete 错误?
C++ New/Delete Error?
我目前正在用 C++ 实现质数筛,我设计的代码应该能够控制筛的大小(通过主函数中的整数文字),但我得到了一些奇怪的错误贯穿始终。我有几年没用过 C++了,但我记得使用 new
和 delete
运算符来管理堆内存。
我的问题如下...
该程序适用于某些筛网尺寸,但不适用于其他筛网尺寸,并且效果不是严格线性的。例如,如果我将筛子设置为 10,000,程序 运行 没问题,但如果我将其设置为 1,000,程序就会崩溃,并显示一条相当神秘(就我的经验而言)的消息,该消息总是引导我到有关 C malloc 断言错误的页面(通过 google)。此外,该程序在 10,000 个 和 删除语句的情况下工作正常,但如果我 运行 通过 valgrind
和另一个无用的(对我来说)消息,它将崩溃。结果,我什至无法在自己的 DX 上调试该死的东西
有什么妙语吗?
特别是,为什么程序会因 较小的 输入而崩溃?从理论上讲,这会 less 可能导致堆错误,不是吗?此外,为什么 valgrind
无法 运行 该程序,而它本身可以正常运行?我怀疑(再次)这与 new/delete 运算符的错误或丑陋使用有关,但我不完全确定。令我特别困惑的部分(关于 valgrind
)是它在错误中提到我在 unsigned long
上使用了 new
运算符,据我所知 -不是我所做的(至少不是具体的)。我认为这是一些我不熟悉的与编译器相关的细节,但我也不确定。
代码(带有 delete 语句;适用于大小 10,000,但不适用于 valgrind
):
using namespace std;
#include <iostream>
#include <cstdlib>
#include <map>
#include <string>
long count_primes(bool* sieve,int size)
{
long count = 0;
for (int a=0;a<size;a++)
{
if (sieve[a])
{
count++;
}
}
return count;
}
int next_prime(bool* primes_so_far,int current_prime,int size)
{
for (int a=current_prime+1;a<size;a++)
{
if (primes_so_far[a]) return a;
}
return -2;
}
int prime_number_sieve(int* primes,int size)
{
if (size<4) return -2;
bool* sieve = new bool[size];
for (int a=0;a<size;a++)
sieve[a] = true;
sieve[0] = false;
sieve[1] = false;
int a=2;
do
{
int b = a;
if (b*a < size) sieve[b*a] = false;
do
{
b++;
sieve[b*a] = false;
} while (b*a < size);
a = next_prime(sieve,a,size);
} while (a*a < size);
long prime_list_size = (long) count_primes(sieve,size);
int* prime_list = new int[prime_list_size];
for (int b=0,c=0;b<size;b++)
{
if (sieve[b]) prime_list[c++] = b;
}
srand(time(NULL));
int rand_int1 = rand();
int rand_int2 = rand();
long rand_num1 = (((long) rand_int1) * prime_list_size)/RAND_MAX;
long rand_num2 = (((long) rand_int2) * prime_list_size)/RAND_MAX;
primes[0] = prime_list[rand_num1];
primes[1] = prime_list[rand_num2];
delete[] sieve;
delete[] prime_list;
return 0;
}
int main()
{
int* prime = new int[2];
prime_number_sieve(prime,10000);
cout << "\n";
cout << prime[0];
cout << "\n";
cout << prime[1];
cout << "\n";
return 0;
}
valgrind
以上错误:
==23738== Invalid write of size 1
==23738== at 0x400A4B: prime_number_sieve(int*, int) (in /home/botch/Downloads/unsorted/bre_final/a.out)
==23738== by 0x400C31: main (in /home/botch/Downloads/unsorted/bre_final/a.out)
==23738== Address 0x5ab83e0 is 0 bytes after a block of size 10,000 alloc'd
==23738== at 0x4C2E80F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==23738== by 0x4009CD: prime_number_sieve(int*, int) (in /home/botch/Downloads/unsorted/bre_final/a.out)
==23738== by 0x400C31: main (in /home/botch/Downloads/unsorted/bre_final/a.out)
==23738==
valgrind: m_mallocfree.c:303 (get_bszB_as_is): Assertion 'bszB_lo == bszB_hi' failed.
valgrind: Heap block lo/hi size mismatch: lo = 4063233, hi = 0.
This is probably caused by your program erroneously writing past the
end of a heap block and corrupting heap metadata. If you fix any
invalid writes reported by Memcheck, this assertion failure will
probably go away. Please try that before reporting this as a bug.
将大小更改为 1,000 时出错:
a.out: malloc.c:2392: sysmalloc: Assertion `(old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)' failed.
Aborted (core dumped)
编辑:
我非常感谢所有(实际)帮助!多亏了下面的答案,该程序现在将 运行 大多数输入(当然不是 太大 大),但我仍然收到 Valgrind 错误。我不太介意 that,但我很想知道发生了什么。我尝试了下面的建议,将随机素数的选择机制更改为 (((long) rand_int1) % prime_list_size);
而不是 (((long) rand_int1) * prime_list_size)/RAND_MAX
,但我在 Valgrind 方面没有明显的结果。我仍然无法准确判断无效堆写入的来源。我将修改代码以查看是否是我的删除导致的并会报告回来。
循环
do
{
b++;
sieve[b*a] = false;
} while (b*a < size);
在检查 b*a < size
之前对 sieve[b*a]
进行赋值。这允许分配一个元素超过数组的末尾。这是此循环最后一次迭代的未定义行为。
你最好使用 std::vector<bool>
[注意它有一些其他向量没有的限制] 或 std::bitset
,而不是手动使用运算符 new
和delete
。请记住,仍然有必要确保您的代码不会从标准容器的末端掉落。
我在您的代码中发现了两个问题。
第一个来了:
do
{
b++;
sieve[b*a] = false;
} while (b*a < size);
这不能防止写入超出限制 size
,因为检查发生在 赋值 `sieve[b*a] = false;
之后
while (b*a < size)
{
sieve[b*a] = false;
b++;
}
我看到的另一个问题是:
long rand_num1 = (((long) rand_int1) * prime_list_size)/RAND_MAX;
long rand_num2 = (((long) rand_int2) * prime_list_size)/RAND_MAX;
乘法中的项可能会导致溢出。我猜你想得到一个小于 size
的随机索引?你可以简单地这样做:
long rand_num1 = (((long) rand_int1) % prime_list_size);
long rand_num2 = (((long) rand_int2) % prime_list_size);
当然这不会产生完美的均匀分布,但它会起作用。为了获得更好的分布,请查看 std 库的数字随机生成器及其 vector
,这对于您正在做的事情来说是一个非常好的工具。
我目前正在用 C++ 实现质数筛,我设计的代码应该能够控制筛的大小(通过主函数中的整数文字),但我得到了一些奇怪的错误贯穿始终。我有几年没用过 C++了,但我记得使用 new
和 delete
运算符来管理堆内存。
我的问题如下...
该程序适用于某些筛网尺寸,但不适用于其他筛网尺寸,并且效果不是严格线性的。例如,如果我将筛子设置为 10,000,程序 运行 没问题,但如果我将其设置为 1,000,程序就会崩溃,并显示一条相当神秘(就我的经验而言)的消息,该消息总是引导我到有关 C malloc 断言错误的页面(通过 google)。此外,该程序在 10,000 个 和 删除语句的情况下工作正常,但如果我 运行 通过 valgrind
和另一个无用的(对我来说)消息,它将崩溃。结果,我什至无法在自己的 DX 上调试该死的东西
有什么妙语吗?
特别是,为什么程序会因 较小的 输入而崩溃?从理论上讲,这会 less 可能导致堆错误,不是吗?此外,为什么 valgrind
无法 运行 该程序,而它本身可以正常运行?我怀疑(再次)这与 new/delete 运算符的错误或丑陋使用有关,但我不完全确定。令我特别困惑的部分(关于 valgrind
)是它在错误中提到我在 unsigned long
上使用了 new
运算符,据我所知 -不是我所做的(至少不是具体的)。我认为这是一些我不熟悉的与编译器相关的细节,但我也不确定。
代码(带有 delete 语句;适用于大小 10,000,但不适用于 valgrind
):
using namespace std;
#include <iostream>
#include <cstdlib>
#include <map>
#include <string>
long count_primes(bool* sieve,int size)
{
long count = 0;
for (int a=0;a<size;a++)
{
if (sieve[a])
{
count++;
}
}
return count;
}
int next_prime(bool* primes_so_far,int current_prime,int size)
{
for (int a=current_prime+1;a<size;a++)
{
if (primes_so_far[a]) return a;
}
return -2;
}
int prime_number_sieve(int* primes,int size)
{
if (size<4) return -2;
bool* sieve = new bool[size];
for (int a=0;a<size;a++)
sieve[a] = true;
sieve[0] = false;
sieve[1] = false;
int a=2;
do
{
int b = a;
if (b*a < size) sieve[b*a] = false;
do
{
b++;
sieve[b*a] = false;
} while (b*a < size);
a = next_prime(sieve,a,size);
} while (a*a < size);
long prime_list_size = (long) count_primes(sieve,size);
int* prime_list = new int[prime_list_size];
for (int b=0,c=0;b<size;b++)
{
if (sieve[b]) prime_list[c++] = b;
}
srand(time(NULL));
int rand_int1 = rand();
int rand_int2 = rand();
long rand_num1 = (((long) rand_int1) * prime_list_size)/RAND_MAX;
long rand_num2 = (((long) rand_int2) * prime_list_size)/RAND_MAX;
primes[0] = prime_list[rand_num1];
primes[1] = prime_list[rand_num2];
delete[] sieve;
delete[] prime_list;
return 0;
}
int main()
{
int* prime = new int[2];
prime_number_sieve(prime,10000);
cout << "\n";
cout << prime[0];
cout << "\n";
cout << prime[1];
cout << "\n";
return 0;
}
valgrind
以上错误:
==23738== Invalid write of size 1
==23738== at 0x400A4B: prime_number_sieve(int*, int) (in /home/botch/Downloads/unsorted/bre_final/a.out)
==23738== by 0x400C31: main (in /home/botch/Downloads/unsorted/bre_final/a.out)
==23738== Address 0x5ab83e0 is 0 bytes after a block of size 10,000 alloc'd
==23738== at 0x4C2E80F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==23738== by 0x4009CD: prime_number_sieve(int*, int) (in /home/botch/Downloads/unsorted/bre_final/a.out)
==23738== by 0x400C31: main (in /home/botch/Downloads/unsorted/bre_final/a.out)
==23738==
valgrind: m_mallocfree.c:303 (get_bszB_as_is): Assertion 'bszB_lo == bszB_hi' failed.
valgrind: Heap block lo/hi size mismatch: lo = 4063233, hi = 0.
This is probably caused by your program erroneously writing past the
end of a heap block and corrupting heap metadata. If you fix any
invalid writes reported by Memcheck, this assertion failure will
probably go away. Please try that before reporting this as a bug.
将大小更改为 1,000 时出错:
a.out: malloc.c:2392: sysmalloc: Assertion `(old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)' failed.
Aborted (core dumped)
编辑:
我非常感谢所有(实际)帮助!多亏了下面的答案,该程序现在将 运行 大多数输入(当然不是 太大 大),但我仍然收到 Valgrind 错误。我不太介意 that,但我很想知道发生了什么。我尝试了下面的建议,将随机素数的选择机制更改为 (((long) rand_int1) % prime_list_size);
而不是 (((long) rand_int1) * prime_list_size)/RAND_MAX
,但我在 Valgrind 方面没有明显的结果。我仍然无法准确判断无效堆写入的来源。我将修改代码以查看是否是我的删除导致的并会报告回来。
循环
do
{
b++;
sieve[b*a] = false;
} while (b*a < size);
在检查 b*a < size
之前对 sieve[b*a]
进行赋值。这允许分配一个元素超过数组的末尾。这是此循环最后一次迭代的未定义行为。
你最好使用 std::vector<bool>
[注意它有一些其他向量没有的限制] 或 std::bitset
,而不是手动使用运算符 new
和delete
。请记住,仍然有必要确保您的代码不会从标准容器的末端掉落。
我在您的代码中发现了两个问题。
第一个来了:
do
{
b++;
sieve[b*a] = false;
} while (b*a < size);
这不能防止写入超出限制 size
,因为检查发生在 赋值 `sieve[b*a] = false;
while (b*a < size)
{
sieve[b*a] = false;
b++;
}
我看到的另一个问题是:
long rand_num1 = (((long) rand_int1) * prime_list_size)/RAND_MAX;
long rand_num2 = (((long) rand_int2) * prime_list_size)/RAND_MAX;
乘法中的项可能会导致溢出。我猜你想得到一个小于 size
的随机索引?你可以简单地这样做:
long rand_num1 = (((long) rand_int1) % prime_list_size);
long rand_num2 = (((long) rand_int2) % prime_list_size);
当然这不会产生完美的均匀分布,但它会起作用。为了获得更好的分布,请查看 std 库的数字随机生成器及其 vector
,这对于您正在做的事情来说是一个非常好的工具。