jjzjj

c++ - 全局重载运算符 new/new[] delete/delete[] C++

coder 2024-02-25 原文

我有这个重载 operator new 和 delete 的示例代码

#include <iostream>
#include <cstddef>
#include <new>

#ifdef USE_ZMALLOC
extern "C" {
#include "zmalloc.h"
}
#define m_malloc zmalloc
#define m_free zfree
#else
#ifdef USE_JEMALLOC
#include <jemalloc/jemalloc.h>
#define m_malloc je_malloc
#define m_free je_free
#else
#include "malloc.h"
#define m_malloc std::malloc
#define m_free std::free
#endif
#endif

// C++ requires that operator new return a legitimate pointer
//  even when zero bytes are requested. That's why if (size == 0) size = 1
void* operator new (std::size_t size) throw (std::bad_alloc) {
  using namespace std;
  if (size == 0) { // Handle 0-byte requests by treating them as 1-byte requests
    size = 1;
  }

  while (true) {
    void* mem = m_malloc(size);

    if (mem != nullptr) {
      return mem;
    } 

    new_handler global_handler = set_new_handler(nullptr);
    set_new_handler(global_handler);

    if (global_handler) {
      (*global_handler)();
    } else {
      throw bad_alloc();
    }

  }
}

void* operator new[] (std::size_t size) throw (std::bad_alloc) {
  return operator new(size);
}

void operator delete (void* ptr) throw() {
  if (ptr == nullptr) {
    return;
  }

  m_free(ptr);
}

void operator delete[] (void* ptr) throw() {
  operator delete(ptr);
}

这段代码确实有效,一切似乎都是正确的。 我的问题是:在使用 valgrind 时,如果我这样做:

int main() {
  Foo** foo = new Foo*[10];

  std::cout << "# " << zmalloc_used_memory() << "." << std::endl;

  delete foo;  // Using wrong delete operator

  return 0;
}

valgrind 不会提示使用了错误的删除运算符。 如果我使用默认的 operator new/delete 对,valgrind 会警告我有关 operator delete 的错误。

1) 我的新/删除运算符有问题吗?
2) valgrind 不再警告此类错误是否正常?

谢谢!

最佳答案

首先,这些不是重载(因为它们具有完全相同的原型(prototype))。这些是替代品。

问题很可能是 Valgrind 不知道您已经替换了这些全局运算符。如果您在共享库中进行替换,Valgrind 将看到函数和原型(prototype)并将能够 Hook 它们。但是,如果替换是在您的可执行文件本身中,您将需要告诉 Valgrind。我认为这可以通过检测代码来实现,但这非常困难。一种更简单的方法是使用 Valgrind 选项 --soname-synonyms=somalloc=NONE。

更新: 我不确定 OP 使用的是哪个版本的 Valgrind,但自 Valgrind 3.12.0(2016 年 10 月 20 日)以来,您不需要任何选项来检测用户替换 malloc/new。

我使用 Valgrind 3.20.0(来自 git HEAD,2022 年 6 月)获得的输出是

==5989== Mismatched free() / delete / delete []
==5989==    at 0x4030741: operator delete(void*, unsigned long) (vg_replace_malloc.c:947)
==5989==    by 0x4012D9: main (in /home/pafloyd/scratch/vg_examples/so_replace_new/srn)
==5989==  Address 0x5328c80 is 0 bytes inside a block of size 80 alloc'd
==5989==    at 0x402F103: operator new[](unsigned long) (vg_replace_malloc.c:652)
==5989==    by 0x4012BF: main (in /home/pafloyd/scratch/vg_examples/so_replace_new/srn)

关于c++ - 全局重载运算符 new/new[] delete/delete[] C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43990978/

有关c++ - 全局重载运算符 new/new[] delete/delete[] C++的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby-on-rails - Enumerator.new 如何处理已通过的 block ? - 2

    我在理解Enumerator.new方法的工作原理时遇到了一些困难。假设文档中的示例:fib=Enumerator.newdo|y|a=b=1loopdoy[1,1,2,3,5,8,13,21,34,55]循环中断条件在哪里,它如何知道循环应该迭代多少次(因为它没有任何明确的中断条件并且看起来像无限循环)? 最佳答案 Enumerator使用Fibers在内部。您的示例等效于:require'fiber'fiber=Fiber.newdoa=b=1loopdoFiber.yieldaa,b=b,a+bendend10.times.m

  3. ruby - 触发器 ruby​​ 中 3 点范围运算符和 2 点范围运算符的区别 - 2

    请帮助我理解范围运算符...和..之间的区别,作为Ruby中使用的“触发器”。这是PragmaticProgrammersguidetoRuby中的一个示例:a=(11..20).collect{|i|(i%4==0)..(i%3==0)?i:nil}返回:[nil,12,nil,nil,nil,16,17,18,nil,20]还有:a=(11..20).collect{|i|(i%4==0)...(i%3==0)?i:nil}返回:[nil,12,13,14,15,16,17,18,nil,20] 最佳答案 触发器(又名f/f)是

  4. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  5. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  6. ruby - 带括号和 splat 运算符的并行赋值 - 2

    我明白了:x,(y,z)=1,*[2,3]x#=>1y#=>2z#=>nil我想知道为什么z的值为nil。 最佳答案 x,(y,z)=1,*[2,3]右侧的splat*是内联扩展的,所以它等同于:x,(y,z)=1,2,3左边带括号的列表被视为嵌套赋值,所以它等价于:x=1y,z=23被丢弃,而z被分配给nil。 关于ruby-带括号和splat运算符的并行赋值,我们在StackOverflow上找到一个类似的问题: https://stackoverflow

  7. ruby - 在 RSpec 中 stub /模拟全局常量 - 2

    我有一个gem,它有一个根据Rails.env的不同行为的方法:defself.envifdefined?(Rails)Rails.envelsif...现在我想编写一个规范来测试这个代码路径。目前我是这样做的:Kernel.const_set(:Rails,nil)Rails.should_receive(:env).and_return('production')...没关系,只是感觉很丑。另一种方法是在spec_helper中声明:moduleRails;end而且效果也很好。但也许有更好的方法?理想情况下,这应该有效:rails=double('Rails')rails.sho

  8. ruby - 将全局 $stdout 重新分配给控制台 - ruby - 2

    我正在尝试将$stdout设置为临时写入一个文件,然后返回到一个文件。test.rb:old_stdout=$stdout$stdout.reopen("mytestfile.out",'w+')puts"thisgoesinmytestfile"$stdout=old_stdoutputs"thisshouldbeontheconsole"$stdout.reopen("mytestfile1.out",'w+')puts"thisgoesinmytestfile1:"$stdout=old_stdoutputs"thisshouldbebackontheconsole"这是输出。r

  9. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

  10. ruby - 在模块/类之间共享全局记录器 - 2

    在许多ruby​​类之间共享记录器实例的最佳(正确)方法是什么?现在我只是将记录器创建为全局$logger=Logger.new变量,但我觉得有更好的方法可以在不使用全局变量的情况下执行此操作。如果我有以下内容:moduleFooclassAclassBclassC...classZend在所有类之间共享记录器实例的最佳方式是什么?我是以某种方式在Foo模块中声明/创建记录器还是只是使用全局$logger没问题? 最佳答案 在模块中添加常量:moduleFooLogger=Logger.newclassAclassBclassC..

随机推荐