Are there cases where a class declares virtual methods and the compiler does not need to use a vptr?

StackOverflow https://stackoverflow.com/questions/2336107

  •  22-09-2019
  •  | 
  •  

문제

I was wondering if there is a possible optimization where the compiler does not need to assign a vptr to an instantiated object even though the object's type is a class with virtual methods.

For example consider:

#include <iostream>
struct FooBase
{
  virtual void bar()=0;
};

struct FooDerived : public FooBase
{
  virtual void bar() { std::cout << "FooDerived::bar()\n"; }
};

int main()
{
   FooBase* pFoo = new FooDerived();
   pFoo->bar();

  return 0;
}

In this example the compiler surely knows what will be the type of pFoo at compile time, so it does not need to use a vptr for pFoo, right? Are there more interesting cases where the compiler can avoid using a vptr?

도움이 되었습니까?

해결책

Building on Andrew Stein's answer, because I think you also want to know when the so-called "runtime overhead of virtual functions" can be avoided. (The overhead is there, but it's tiny, and rarely worth worrying about.)

It's really hard to avoid the space of the vtable pointer, but the pointer itself can be ignored, including in your example. Because pFoo's initialization is in that scope, the compiler knows that pFoo->bar must mean FooDerived::bar, and doesn't need to check the vtable. There are also several caching techniques to avoid multiple vtable lookups, ranging from the simple to the complex.

다른 팁

Even in the case you show, I doubt that any compiler will do what you suggest.

You are using a very simple program all in one file.

Imagine that you had FooBase and FooDerived in Foo.h and Foo.cpp and main in main.cpp. When compiling Foo.cpp, how is the compiler to know that in the whole program there is no need for a vtbl. It has not seen main.cpp.

The final determination can only be made at link time, when it is way too late and complicated to modify the object file, find all the calls to sizeof(FooDerived), etc.

DATE() SQL에서 기능. 염두에 두어야 할 두 가지가 있습니다.

  1. 데이터베이스 내부의 모든 것이 UTC 및 모든 것이 DATE()의 결과를 포함합니다.
  2. 현지 시간대의 단일 날짜 (즉,)는 UTC에서 두 개의 날짜를 쉽게 교차 할 수 있으므로 (UTC) 대신 전체 시간 소인 ( 모두 면 모두)을 볼 필요가 있습니다. 날짜 구성 요소.

    이렇게 작용해야합니다 :

    now = Time.now
    Entry.where('created_at between :start and :end and email = :email',
        :start => now.beginning_of_day,
        :end   => now.end_of_day,
        :email => email
    )
    
    .

    시간은 자동으로 UTC로 변환되어야합니다. 상한을 조금 다르게 처리하고 싶을 수도 있습니다. end_of_day를 사용하면 23:59:59를 사용하므로 캡처하고자하는 것을 통해 미끄러지려는 객실이 있습니다. 이와 같이 SQL의 between를 사용하는 닫힌 간격이 아닌 명시 적 반 개방 간격을 사용하여 해당 문제를 해결할 수 있습니다.

    now = Time.now
    Entry.where('created_at >= :start and created_at < :end and email = :email',
        :start => now.beginning_of_day,
        :end   => now.tomorrow.beginning_of_day,
        :email => email
    )
    
    .

It is possible for a compiler to cut out the indirection overhead of virtual function calls when it knows which exact class's method is going to be invoked. This is the result of a form of points-to analysis that optimizing compilers do. They trace the data flow of pointer variables, and any place a pointer can only point to objects of one type, it can generate calls for exactly that type, implementing virtual call semantics statically (i.e. at compile time).

As many others have said, unless the compiler is doing whole-program/link-time optimization (becoming more popular; GCC gains it in 4.5), it still needs to generate some sort of table of virtual functions to support separate compilation.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top