【问题标题】:Testing constructor initialization list测试构造函数初始化列表
【发布时间】:2012-10-25 07:51:34
【问题描述】:

我正在做一个测试,检查是否所有类属性都在构造函数中初始化。 我当前的解决方案适用于非指针属性:

void CSplitVectorTest::TestConstructorInitialization()
{
    const size_t memorySize = sizeof(CSplitVector);
    char* pBuffer1 = (char*) malloc(memorySize);
    char* pBuffer2 = (char*) malloc(memorySize);
    memset(pBuffer1,'?',memorySize);
    memset(pBuffer2,'-',memorySize);
    new(pBuffer1) CSplitVector;
    new(pBuffer2) CSplitVector;
    const bool bObjectsAreEqual = memcmp(pBuffer1,pBuffer2,memorySize)==0;
    if (!TEST(bObjectsAreEqual))
    {
        COMMENT("Constructor initialization list not complete!");
    }
    free(pBuffer1);
    free(pBuffer2);
}

您知道如何改进测试指针是否已初始化吗?

【问题讨论】:

  • 你的方法行不通。编译器可能会在数据成员之间插入填充。
  • @Lol4t0:未被任何数据成员占用的字节将在第一个缓冲区中保留?,在第二个缓冲区中保留-
  • 指针不能用是什么意思?
  • @Marek 啊,当然。在下面增加了我的答案(最后一段)。
  • 对于指针,只要我可以使用智能指针,否则我有受控变量的安全指针:snapwebsites.org/project/controlled-vars 我也将它用于所有基本数据类型(int、char 等)这样,无论如何,一切都会被初始化。特别是,如果您将变量标记为“需要初始化”,那么您必须在您的类中有一个初始化程序。所以你不会错过的。

标签: c++ unit-testing


【解决方案1】:

您的测试检查对象的每个字节是否已被构造函数覆盖。作为一个直接的内存检查,它看起来不错,但如果该类包含其他不一定完全初始化自己的对象,您可能会遇到麻烦。

也就是说,我的主要问题是:这真的是一个有效的测试吗?例如,CSplitVector 类中的每个属性都由初始化列表初始化是否至关重要?您是否有一些此时可能不需要初始化?另外,如何检查属性是否设置为您期望的值?

【讨论】:

    【解决方案2】:

    而不是逐字节比较,您可能应该使用正确的填充或字长,并测试每个字的 any 字节是否被初始化。这样,您可能会使用填充和构造函数绕过编译器,在填充的短于单词的字段之间留下未初始化的字节。

    要测试真正的填充大小,从臀部拍摄,下面的代码应该非常可靠:

    struct PaddingTest {
      volatile char c; // volatile probably not needed, but will not hurt either
      volatile int i;
    
      static int getCharPadding() { 
        PaddingTest *t = new PaddingTest;
        int diff = (int)(&(t->i)) - (int)&((t->c));
        delete t;
        return diff;
      }
    }
    

    编辑:你仍然需要这两个对象,但你不再将它们相互比较,你只需将每个初始化的数据与 memset 值进行比较,如果任何一个对象有任何变化,就意味着这个词被触摸了(也在另一个,它只是有可能被初始化为与你 memset 相同的值)。

    【讨论】:

      【解决方案3】:

      我找到了解决上述问题的方法,并使用已初始化/未初始化的指针和不同的长度类型对其进行了测试。

      在测试头中我添加了#pragma pack(1)(我正在研究gcc)

      #pragma pack(1)
      #include <CSplitVector>
      

      测试有点复杂:

      void CSplitVectorTest::TestConstructorInitialization()
      {
          const size_t memorySize = sizeof(CSplitVector);
          char* pBuffer = (char*) malloc(memorySize);
          memset(pBuffer,'?',memorySize);
          CSplitVector* pSplitVector = new(pBuffer) CSplitVector;
      
          // find pointers for all '?'
          QList<char*> aFound;
          char* pFoundChar = (char*) memchr(pBuffer,'?',memorySize);
          while (pFoundChar)
          {
              aFound.append(pFoundChar);
              char* pStartFrom = pFoundChar+1;
              pFoundChar = (char*) memchr(pStartFrom,'?',memorySize-(int)(pStartFrom-pBuffer));
          }
          // if there are any '?'....
          if (aFound.count())
          {
              // allocate the same area with '-'...
              pSplitVector->~CSplitVector();
              memset(pBuffer,'-',memorySize);
              pSplitVector = new(pBuffer) CSplitVector;
              // and check if places found before contain '-'
              while (aFound.count())
              {
                  pFoundChar = aFound.takeFirst();
                  if (*pFoundChar=='-')
                  {
                      // if yes then class has uninitialized attribute
                      TEST_FAILED("Constructor initialization list not complete!");
                      pSplitVector->~CSplitVector();
                      free(pBuffer);
                      return;
                  }
              }
          }
          // if no then all attributes are initialized
          pSplitVector->~CSplitVector();
          free(pBuffer);
          TEST(true);
      }
      

      请随时指出此解决方案中的任何缺陷。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-03-19
        • 1970-01-01
        • 2017-05-02
        • 2018-06-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多