ich die Leistung der folgenden Methoden von C++ Polymorphismus Vergleich:Static Polymorphismus mit Boost Variante einzelnen Besucher vs Multi Besucher vs dynamische Polymorphie
Methode [1]. Statischer Polymorphismus unter Verwendung von Boost-Varianten mit einem separaten Besucher für jede Methode Methode [2]. Statischer Polymorphismus unter Verwendung von Boost-Varianten mit einem einzelnen Besucher, der eine andere Methode mit Methodenüberladung aufruft Methode [3]. Einfache alte dynamische Polymorphie
Plattform: - Intel x86 64 Bit Red Hat moderner Multi-Core-Prozessor, 32 GB RAM - gcc (GCC) 4.8.1 mit -O2 Optimierung - Erhöhung 1.6.0
einige Ergebnisse:
- Methode [1] zu haben scheint deutlich outperform Methoden [2] und [3]
- Methode [3] übertrifft Methode [2] die meiste Zeit
Meine Frage ist, warum Methode [2], wo ich einen Besucher benutze, aber Methodenüberladung verwenden, um die richtige Methode aufzurufen, schlechtere Leistung als virtuelle Methoden. Ich würde erwarten, dass der statische Polymorphismus besser ist als der dynamische Polymorphismus. Ich verstehe, dass es einige Kosten für den zusätzlichen Parameter gibt, der in Methode [2] übergeben wird, um die visit() -Methode der Klasse, die aufgerufen werden soll, und möglicherweise noch mehr Verzweigungen aufgrund von Methodenüberladung anzugeben? Aber shouldn "t noch diese virtuelle Methoden entwickeln
-Code ist unter:.
// qcpptest.hpp
#ifndef INCLUDED_QCPPTEST_H
#define INCLUDED_QCPPTEST_H
#include <boost/variant.hpp>
class IShape {
public:
virtual void rotate() = 0;
virtual void spin() = 0;
};
class Square : public IShape {
public:
void rotate() {
// std::cout << "Square:I am rotating" << std::endl;
}
void spin() {
// std::cout << "Square:I am spinning" << std::endl;
}
};
class Circle : public IShape {
public:
void rotate() {
// std::cout << "Circle:I am rotating" << std::endl;
}
void spin() {
// std::cout << "Circle:I am spinning" << std::endl;
}
};
// template variation
// enum class M {ADD, DEL};
struct ADD {};
struct DEL {};
class TSquare {
int i;
public:
void visit(const ADD& add) {
this->i++;
// std::cout << "TSquare:I am rotating" << std::endl;
}
void visit(const DEL& del) {
this->i++;
// std::cout << "TSquare:I am spinning" << std::endl;
}
void spin() {
this->i++;
// std::cout << "TSquare:I am rotating" << std::endl;
}
void rotate() {
this->i++;
// std::cout << "TSquare:I am spinning" << std::endl;
}
};
class TCircle {
int i;
public:
void visit(const ADD& add) {
this->i++;
// std::cout << "TCircle:I am rotating" << std::endl;
}
void visit(const DEL& del) {
this->i++;
// std::cout << "TCircle:I am spinning" << std::endl;
}
void spin() {
this->i++;
// std::cout << "TSquare:I am rotating" << std::endl;
}
void rotate() {
this->i++;
// std::cout << "TSquare:I am spinning" << std::endl;
}
};
class MultiVisitor : public boost::static_visitor<void> {
public:
template <typename T, typename U>
void operator()(T& t, const U& u) {
// std::cout << "visit" << std::endl;
t.visit(u);
}
};
// separate visitors, single dispatch
class RotateVisitor : public boost::static_visitor<void> {
public:
template <class T>
void operator()(T& x) {
x.rotate();
}
};
class SpinVisitor : public boost::static_visitor<void> {
public:
template <class T>
void operator()(T& x) {
x.spin();
}
};
#endif
// qcpptest.cpp
#include <iostream>
#include "qcpptest.hpp"
#include <vector>
#include <boost/chrono.hpp>
using MV = boost::variant<ADD, DEL>;
// MV const add = M::ADD;
// MV const del = M::DEL;
static MV const add = ADD();
static MV const del = DEL();
void make_virtual_shapes(int iters) {
// std::cout << "make_virtual_shapes" << std::endl;
std::vector<IShape*> shapes;
shapes.push_back(new Square());
shapes.push_back(new Circle());
boost::chrono::high_resolution_clock::time_point start =
boost::chrono::high_resolution_clock::now();
for (int i = 0; i < iters; i++) {
for (IShape* shape : shapes) {
shape->rotate();
shape->spin();
}
}
boost::chrono::nanoseconds nanos =
boost::chrono::high_resolution_clock::now() - start;
std::cout << "make_virtual_shapes took " << nanos.count() * 1e-6
<< " millis\n";
}
void make_template_shapes(int iters) {
// std::cout << "make_template_shapes" << std::endl;
using TShapes = boost::variant<TSquare, TCircle>;
// using MV = boost::variant<M>;
// xyz
std::vector<TShapes> tshapes;
tshapes.push_back(TSquare());
tshapes.push_back(TCircle());
MultiVisitor mv;
boost::chrono::high_resolution_clock::time_point start =
boost::chrono::high_resolution_clock::now();
for (int i = 0; i < iters; i++) {
for (TShapes& shape : tshapes) {
boost::apply_visitor(mv, shape, add);
boost::apply_visitor(mv, shape, del);
// boost::apply_visitor(sv, shape);
}
}
boost::chrono::nanoseconds nanos =
boost::chrono::high_resolution_clock::now() - start;
std::cout << "make_template_shapes took " << nanos.count() * 1e-6
<< " millis\n";
}
void make_template_shapes_single(int iters) {
// std::cout << "make_template_shapes_single" << std::endl;
using TShapes = boost::variant<TSquare, TCircle>;
// xyz
std::vector<TShapes> tshapes;
tshapes.push_back(TSquare());
tshapes.push_back(TCircle());
SpinVisitor sv;
RotateVisitor rv;
boost::chrono::high_resolution_clock::time_point start =
boost::chrono::high_resolution_clock::now();
for (int i = 0; i < iters; i++) {
for (TShapes& shape : tshapes) {
boost::apply_visitor(rv, shape);
boost::apply_visitor(sv, shape);
}
}
boost::chrono::nanoseconds nanos =
boost::chrono::high_resolution_clock::now() - start;
std::cout << "make_template_shapes_single took " << nanos.count() * 1e-6
<< " millis\n";
}
int main(int argc, const char* argv[]) {
std::cout << "Hello, cmake" << std::endl;
int iters = atoi(argv[1]);
make_virtual_shapes(iters);
make_template_shapes(iters);
make_template_shapes_single(iters);
return 0;
}
Dieses Programm segmentiert für mich, wenn es mit "-O3" kompiliert wird. Bist du sicher, dass deine Logik stimmt? –
Nur segfaults, wenn kein argv [1] bereitgestellt wird :) –
Ja, Sie müssen ein Argument wie 10 oder 1000 oder 1000000 angeben. So oft wird die Schleife ausgeführt. – Sid