不总是使用C ++ operator delete override

时间:2018-04-08 02:16:16

标签: c++ new-operator googletest delete-operator

我使用谷歌测试进行了一些C ++单元测试。抛出一些代码来覆盖new / delete操作符以检查单元测试中的泄漏。虽然有问题。一些谷歌测试新/删除使用我的重写方法,但有些没有,所以我在跟踪代码中得到错误 - 有时看到内存泄漏,即使它真的被删除,有时看到malloc返回

这是我的最小新/删除覆盖(只打印手动检查的地址):

void * operator new(size_t size)
{
  void * addr = malloc(size);
  std::cout << "    tracking create: " << addr << "(size " << size << ")" << std::endl;
  return addr;
}
void * operator new[](size_t size)
{
  void * addr = malloc(size);
  std::cout << "    tracking create: " << addr << "(size " << size << ")" << std::endl;
  return addr;
}

void operator delete(void * addr) noexcept
{
  std::cout << "    tracking delete: " << addr << std::endl;
  free(addr);
}

void operator delete[](void * addr) noexcept
{
  std::cout << "    tracking delete: " << addr << std::endl;
  free(addr);
}

这是谷歌测试线,不通过我的重写删除(gtest-port.h):

void reset(T* p = NULL) {
    if (p != ptr_) {
      if (IsTrue(sizeof(T) > 0)) {  // Makes sure T is a complete type.
        delete ptr_;
      }
      ptr_ = p;
    }
  }

当我在gdb中的delete ptr_行中断,然后单步执行,它会直接进入ptr_ = p行,因此没有其他内容覆盖该删除。

我正在构建gtest作为存档文件,并在构建单元测试时将其链接起来。如果它很重要:我正在使用cygwin建立mingw的窗户。

这是一个最小的例子,2个文件min.cpp和minmain.cpp。这是min.cpp:

#include <iostream>
#include <string>

// Overload the new/delete operators to check for memory errors
void * operator new(size_t size)
{
  void * addr = malloc(size);
  std::cout << "    tracking create: " << addr << "(size " << size << ")" << std::endl;
  return addr;
}
void * operator new[](size_t size)
{
  void * addr = malloc(size);
  std::cout << "    tracking create: " << addr << "(size " << size << ")" << std::endl;
  return addr;
}

void operator delete(void * addr) noexcept
{
  std::cout << "    tracking delete: " << addr << std::endl;
  free(addr);
}

void operator delete[](void * addr) noexcept
{
  std::cout << "    tracking delete: " << addr << std::endl;
  free(addr);
}

minmain.cpp:

#include "gtest/gtest.h"

TEST(MinTest, MinimalTest)
{
  int test = 5;
  test++;
  test++;
  test++;
  ASSERT_EQ(test, 8); 
}

int main(int argc, char *argv[])
{
  char* t = new char();
  t[0] = 't'; std::cout << "t is " << t[0] << std::endl;
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

编译:

/bin/x86_64-w64-mingw32-g++.exe -std=c++11 -D_USE_MATH_DEFINES -g -Wall -I../third_party/googletest-1.8.0/googletest/include -c min.cpp -o min.o

创建min.o,然后编译main并链接all:

/bin/x86_64-w64-mingw32-g++.exe -std=c++11 -D_USE_MATH_DEFINES -g -Wall -I../third_party/googletest-1.8.0/googletest/include -o minmain minmain.cpp min.o ../third_party/googletest-1.8.0/googletest/make/gtest_main.a

使用版本1.8.0的gtest,在gtest-port.h:1145处中断以进入delete ptr_行,然后单步执行。

以下是运行上面示例的一些示例输出(前几行输出):

tracking create: 0x30e4c0(size 392)
tracking create: 0xa477e0(size 392)
tracking create: 0xa477e0(size 392)
tracking create: 0xa477e0(size 392)
tracking create: 0xa477e0(size 392)
tracking create: 0xa47b80(size 28)
tracking delete: 0xa47b80

我被跟踪的事实在同一地址创建,中间没有跟踪删除是一个问题,因为在允许再次分配相同地址之间有删除,但这些删除没有通过我的重写删除运算符

为什么gtest中的delete ptr_;行不使用我的重写删除功能?

1 个答案:

答案 0 :(得分:1)

看起来这是MinGW中的一个错误: MinGW bug #634

解决方法是链接libstdc ++的静态版本,而不是让它链接动态库。不是最理想的解决方案,但它对我的单元测试来说足够好,它允许我正确覆盖。

我通过compile / link命令修改了以下内容来执行此操作:

/bin/x86_64-w64-mingw32-g++.exe -std=c++11 -D_USE_MATH_DEFINES -g -Wall -I../third_party/googletest-1.8.0/googletest/include -o minmain minmain.cpp min.o ../third_party/googletest-1.8.0/googletest/make/gtest_main.a /cygdrive/c/cygwin64/lib/gcc/x86_64-w64-mingw32/6.4.0/libstdc++.a

Mucho thanko给了Peter让我走上寻找道路的正确道路。