Wednesday, February 16, 2022

Watch out for virtual function invocation

virtual function

 In some heavily invoked code the following construct was used:

interface ITable
{
   virtual std::string GetData() const = 0;
};

class Table : public ITable
{
public:
   virtual std::string GetData() const override
   {
      return std::string{"1"};
   }
};

class TableCt : public Table
{
public:
   long GetDataCt() const
   {
      const std::string strData = GetData();  // watch out
      return std::stol(strData);
   }
};

Client code invokes 'GetDataCt', e.g.:

void f()
{
    TableCt tbl;
    tbl.GetDataCt();  
}

in the real case TableCt wasn't the final class but GetData will not be overriden anywhere else. The code is functional correct but it takes a performance hit since base class function 'GetData' is invoked through vtable:

    TableCt tbl;
    tbl.GetDataCt();
00007FF653F710BC  lea         rdx,[rsp+30h]  
00007FF653F710C1  lea         rcx,[tbl]  
00007FF653F710C6  call        rax  

  On closer thought this is logical since the compiler must deal with 'GetData' being overwritten by a derived class. Therefore explicitly calling the base class function is needed to tell the compiler that it must use the base class:

class TableCt : public Table
{
   long GetDataCt() const
   {
      return std::stol(__super::GetData());
   }
};

 Using the keyword final could also do the trick too although it depends then on the cleverness of the compiler.

No comments:

Post a Comment

Watch out for atan change in Visual Studio 2022 17.14.6

atan  Recently we updated Visual Studio 2022 17.14.6 and the regression test reported errors. It turned out that atan implementation was cha...