【发布时间】:2018-03-07 07:46:01
【问题描述】:
在使用std::visit / std::variant 时,我在分析器输出中看到std::__detail::__variant::__gen_vtable_impl 函数花费的时间最多。
我做了这样的测试:
// 3 class families, all like this
class ElementDerivedN: public ElementBase
{
...
std::variant<ElementDerived1*, ElementDerived2*,... > GetVariant() override { return this; }
}
std::vector<Element*> elements;
std::vector<Visitor*> visitors;
std::vector<Third*> thirds;
// prepare a hack to get dynamic function object:
template<class... Ts> struct funcs : Ts... { using Ts::operator()...; };
template<class... Ts> funcs(Ts...) -> funcs<Ts...>;
// demo functions:
struct Actions { template < typename R, typename S, typename T> void operator()( R*, S*, T* ) {} };
struct SpecialActionForElement1{ template < typename S, typename T > void operator()( Element1*, S*, T* ) {} };
for ( auto el: elements )
{
for ( auto vis: visitors )
{
for ( auto th: thirds )
{
std::visit( funcs{ Actions(), SpecialActionForElement1Derived1()}, el->GetVariant(), vis->GetVariant(), th->GetVariant() );
}
}
}
如前所述,std::__detail::__variant::__gen_vtable_impl<...> 花费的时间最多。
问:
由于每次访问调用时生成的 n 维函数数组从调用到调用都相同,因此最好将其保留在 std::visit 的调用之间。这可能吗?
也许我走错了路,如果是,请告诉我!
编辑: 使用标准 Fedora 安装中的编译器 gcc7.3。 std-lib 在 g++ 中被用作标准(这是什么)
构建选项:
g++ --std=c++17 -fno-rtti main.cpp -O3 -g -o go
【问题讨论】:
-
你在 std::variant 中使用多态对象吗?也许您可以通过完全避免 std::variant 来简化数据。变体实际上是昂贵的东西,也不是最佳的。如果你使用简单的继承,你给编译器一个机会来优化你的代码,通过去虚拟化等。
-
@VictorGubin:是的,这是众所周知的。原因是标准的访问者模式不能用模板(多分派)实现,因为虚拟模板在 C++ 中是不可能的。因此,使用变体/访问是解决方法。正如所见,当 N=2 时,该解决方案需要多花大约 60% 的时间来调度。这对我来说是可以接受的,但也许可以优化(该问题的原因)。与经典的访问者模式实现一样,我的具体 sw 的设计更简单,更容易阅读变体/访问。示例中的简化并没有反映我真正的软件需求!
-
从我的(不仅仅是我的,比如Thomas Kyte)的角度来看,如果你考虑优化,你应该从设计开始,然后再转向底层。我不认为低水平
-
@VictorGubin:您可以向 XY 提出任何问题。但是这个问题询问了具体功能的潜在优化选项。发现的行为让 me 假设一个对象将生成一个临时对象,该对象可以在调用之间保留。那么这与我的申请有什么关系呢?我进行了测量,发现正是在这一点上消耗了时间。所以我认为要求改进是一个重点。也许这是其他人也可以用来使他们的代码更快的想法。而且这个问题不是“我的程序很慢,请帮忙”。
-
@PaulR:每个变体包含 3 种类型,应该给出一个 3x3 矩阵。这也是我想知道的!
标签: c++ optimization variant visitor-pattern