I am still a beginner and I do not really grasp the purpose of exceptions in a program.
When you throw an exception, you basically skip a (small or big) part of your program, so one of my questions would be : should an exception leads to the end of the program ?
Also, suppose we have a class Rectangle. It would be define by its length and its height like this :
#include <iostream>
using namespace std;
class Rectangle {
public:
Rectangle(double length, double height)
{
if (length > 0 and heigth > 0) {
length_ = length;
height_ = height;
}
else {
// Throw an exception ? Use a convention ?
}
}
// other methods
private:
double length_;
double height_;
};
int main() {
// do stuff
return 0;
}
However, it would not make much sense to have a negative length or height.
So should I throw an exception in the constructor ? Should I use an arbitrary convention and take their absolute value ? Should I prevent the user in the main() from passing negative arguments ?
Yes, in a constructor you do not have any other option to indicate an error but an exception. In cases where you can not assure a valid state of your object it is best to throw one. For example
#include <iostream>
#include <exception>
using namespace std;
struct Rectangle_exception : public std::runtime_error {
Rectangle_exception(const char* const message): std::runtime_error(message) {}
};
class Rectangle {
public:
Rectangle(double length, double height)
{
if (length > 0 && heigth > 0) {
length_ = length;
height_ = height;
}
else {
throw Rectangle_exception{"Invalid dimensions."};
}
}
// other methods
private:
double length_;
double height_;
};
For more informations about exceptions look in this FAQ or for "best practises" to error handling in C++ in the error section of CppCoreGuidelines
Sometimes exceptions are not desirable (because your company decided not to use them) but you still want to have some assertions. The CppCoreGuiidelines proposes Macros (and wants a language feature) named Expects and Ensures. Its planned that you can state preconditions and postconditions in the interface. For now these can be Macros with different behaviour depending on your compiler flags. For implementation details see here or here
class Rectangle {
public:
Rectangle(double length, double height)
{
Expects(length > 0 && height > 0);
length_ = length;
height_ = height;
}
// other methods
private:
double length_;
double height_;
};
Related
I'm trying to create a 2D sidescroller mini-game. For now, I only have a character with a sprite and one animation, which i'm trying to move using the left/right arrows. At first, I only had a Character class, storing the sprite of the character and its running animation. And it worked. But now, I'm trying to add a CharacterManager class, which will create all the characters to avoid doing it in the main, and which will manage their movements and draw them.
And it doesn't work anymore. I think my problems come from the fact that I have trouble using pointers, which I'm not really familiar with.
Here are the different classes I'm using :
Animation.h :
#pragma once
#include <vector>
#include <SFML/Graphics.hpp>
#include <stdexcept>
#include <ctime>
#include "Constants.h"
class Animation {
public:
Animation();
~Animation();
void SetFrames(std::vector<sf::IntRect> frames) { m_frames = frames; }
sf::IntRect Play();
private:
std::vector<sf::IntRect> m_frames;
unsigned int m_currentFrame;
float m_updateTime;
float m_timeSinceLastFrame;
float m_lastCallTimestamp;
float m_currentTimestamp;
bool m_firstCall;
};
Animation.cpp :
#include "Animation.h"
Animation::Animation() {
m_currentFrame = 0;
m_updateTime = 1.0f / ANIMATION_SPEED;
m_timeSinceLastFrame = 0.0f;
m_firstCall = true;
}
Animation::~Animation() {
}
sf::IntRect Animation::Play() {
if (m_frames.size() == 0) {
throw std::length_error("The frames vector is empty");
}
// Advance time and add the elapsed time to timeSinceLastFrame
m_currentTimestamp = std::clock();
// Ignore elapsed time if first call
if (m_firstCall) {
m_timeSinceLastFrame = 0.0f;
m_lastCallTimestamp = m_currentTimestamp;
m_firstCall = false; // Not first call anymore
}
else {
m_timeSinceLastFrame += (m_currentTimestamp - m_lastCallTimestamp) / CLOCKS_PER_SEC;
m_lastCallTimestamp = m_currentTimestamp;
}
// Next frame
if (m_timeSinceLastFrame >= m_updateTime) {
m_currentFrame++;
m_timeSinceLastFrame = 0;
// Check animation end
if (m_currentFrame >= m_frames.size()) {
m_currentFrame = 0; // Reset frame progression
m_firstCall = true; // Next passage will be the first call of a new animation
/* TODO : return something to alert the end of the animation
(like a specific rectint or set a variable to true and get it on the other side) */
}
}
return m_frames[m_currentFrame];
}
Character.h :
#pragma once
#include<string>
#include<iostream>
#include <SFML/Graphics.hpp>
#include <vector>
#include <map>
#include "Constants.h"
#include "Animation.h"
class Character : public sf::Drawable {
public:
Character();
Character(std::string name);
~Character();
void Move(float value);
// Setters
void SetTexture(std::string filename);
void SetPosition(sf::Vector2f pos) { m_position = pos; };
void SetAnimations(std::map<std::string, Animation*> animations) { m_animations = animations; };
protected:
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
std::string m_name;
unsigned int m_orientation; // 0 (default) = right | 1 = left
std::map<std::string, Animation*> m_animations;
Animation runningAnimation;
sf::Vector2f m_position;
sf::Texture m_texture;
sf::Sprite m_sprite;
};
Character.cpp :
#include "Character.h"
Character::Character() {}
Character::Character(std::string name) {
m_name = name;
m_orientation = 0;
runningAnimation = Animation();
}
Character::~Character() {
}
void Character::draw(sf::RenderTarget& target, sf::RenderStates states) const {
target.draw(m_sprite, states);
}
void Character::Move(float value) {
m_sprite.setTextureRect(runningAnimation.Play());
m_position.x += value;
m_sprite.setPosition(m_position);
}
void Character::SetTexture(std::string filename) {
filename = TEXTURE_FILES_PREFIX + filename;
// Load the entire texture file
if (!m_texture.loadFromFile(filename))
std::cout << "Error loading texture file : " << filename << std::endl;
// Set the texture (by default, initialize to idle state) and the position
std::vector<sf::IntRect> runningFrames{
sf::IntRect(67, 45, 19, 28),
sf::IntRect(116, 46, 20, 27),
sf::IntRect(166, 48, 20, 25),
sf::IntRect(217, 45, 22, 28),
sf::IntRect(266, 46, 19, 27),
sf::IntRect(316, 48, 20, 25)
};
runningAnimation.SetFrames(runningFrames);
m_sprite.setTexture(m_texture);
m_sprite.setTextureRect(runningAnimation.Play());
m_sprite.setPosition(m_position);
}
CharacterManager.h :
#pragma once
#include <vector>
#include <map>
#include <iostream>
#include <SFML\Graphics.hpp>
#include "AliveCharacter.h"
#include "Npc.h"
#include "Animation.h"
#include "CharacterStats.h"
enum CharacterType
{
NPC,
ALIVE,
GENERAL
};
// Class containing a vector of character entities and creates the animations of these entities from a data file (later)
class CharacterManager : public sf::Drawable {
public :
CharacterManager();
~CharacterManager();
// Loads the file and stores the content inside data string (not used for now)
void LoadDataFile(std::string filename);
// Create a character and add it to the list
void CreateCharacter(std::string name, std::string textureFilename, CharacterType characterType, sf::Vector2f pos);
void CreateCharacter(std::string name, std::string textureFilename, CharacterType characterType, sf::Vector2f pos, std::map<std::string, Animation*> animations);
void CreateCharacter(std::string name, std::string textureFilename, CharacterType characterType, sf::Vector2f pos, std::map<std::string, Animation*> animations, CharacterStats stats);
void Move(float value);
Character* GetCharacter(std::string name) { return m_characters[name]; }
private :
// Calls the draw() function of each stored Character
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
std::string m_data;
std::map<std::string, Character*> m_characters;
};
CharacterManager.cpp :
#include "CharacterManager.h"
CharacterManager::CharacterManager() {
m_characters = std::map<std::string, Character*>();
}
CharacterManager::~CharacterManager() {
//delete m_characters;
}
void CharacterManager::LoadDataFile(std::string filename) {
// TODO : load file content
}
void CharacterManager::CreateCharacter(std::string name, std::string textureFilename, CharacterType characterType, sf::Vector2f pos) {
Character new_character(name); // Create a generic character...
// ... and specialise it depending on the character type param
switch (characterType)
{
case NPC:
new_character = Npc(name);
break;
case ALIVE:
new_character = AliveCharacter(name);
break;
default:
new_character = Character(name);
break;
}
// Set texture, position and add to the characters list
new_character.SetTexture(textureFilename);
new_character.SetPosition(pos);
m_characters.insert({ name, &new_character });
}
void CharacterManager::CreateCharacter(std::string name, std::string textureFilename, CharacterType characterType, sf::Vector2f pos, std::map<std::string, Animation*> animations) {
CreateCharacter(textureFilename, name, characterType, pos);
m_characters[name]->SetAnimations(animations);
}
void CharacterManager::CreateCharacter(std::string name, std::string textureFilename, CharacterType characterType, sf::Vector2f pos, std::map<std::string, Animation*> animations, CharacterStats stats) {
CreateCharacter(textureFilename, name, characterType, pos);
m_characters[name]->SetAnimations(animations);
//m_characters[name]->SetStats(stats);
}
void CharacterManager::Move(float value) {
for each (std::pair<std::string, Character*> pair in m_characters) {
Character* character = pair.second;
character->Move(value);
}
}
void CharacterManager::draw(sf::RenderTarget& target, sf::RenderStates states) const {
for each (std::pair<std::string, Character*> pair in m_characters) {
Character* character = pair.second;
target.draw(*character);
}
}
And finally the Main.cpp, where you can see in comments the things I tried without success :
#include "Map.h"
#include "CharacterManager.h"
int main()
{
sf::RenderWindow window(sf::VideoMode(WINDOW_SIZE_X, WINDOW_SIZE_Y), WINDOW_TITLE);
window.setFramerateLimit(WINDOW_FRAMERATE);
Map map;
int pos = WINDOW_SIZE_X / 2 - MAP_SIZE_X / 2;
float movement = 0;
map.SetPosition(pos);
map.SetGroundTexture("Foreground/Tileset.png");
map.SetBackgroundTexture("Background/BGFront.png");
CharacterManager charManager;
charManager.CreateCharacter("main", "Characters/test-character.png", ALIVE, sf::Vector2f(400, WINDOW_SIZE_Y - HEIGHT_OF_GROUND - 28));
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
if (event.type == sf::Event::KeyPressed)
{
if (event.key.code == sf::Keyboard::Left)
movement = -MOVING_SPEED;
else if (event.key.code == sf::Keyboard::Right)
movement = MOVING_SPEED;
}
else if (event.type == sf::Event::KeyReleased)
movement = 0;
}
// Move the map
map.Scroll(movement);
//charManager.GetCharacter("main")->Move(movement);
charManager.Move(movement);
window.clear();
window.draw(map);
/*Character* mainPerso = charManager.GetCharacter("main");
window.draw(*mainPerso);*/
window.draw(charManager);
window.display();
}
return 0;
}
The error I'm getting is on the return m_frames[m_currentFrame] line in Animation.cpp, in the end of the Play() function. A pop-up window opens saying : "Expression: vector subscript out of range". This error only happens the second time the code goes through this line. The first time it's called from the SetTexture() function of Character.cpp (m_sprite.setTextureRect(runningAnimation.Play())), itself called from the CreateCharacter() function of the CharacterManager (new_character.SetTexture(textureFilename)), and at this point the Animation object looks as it should.
But the second time, it's called from the Move() function of Character (m_sprite.setTextureRect(runningAnimation.Play())), itself called from the Move() function of the CharacterManager (character->Move(value)). And at this point, all of the Animation object absolutely doesn't look like it should. In debug mode, I can see this :
Debug screenshot
As I said earlier, I think the problem comes from the use of pointers. When I'm trying to remove them, the code runs, but I get a white square problem.
I tried to find some sort of tutorial on how to use this kind of architecture, but didn't find anything relevant. If you know one, I'll be glad to look at it.
As I said earlier, I think the problem comes from the use of pointers.
When I'm trying to remove them, the code runs, but I get a white
square problem.
yep, it is a common issue for SFML when using Texture and Sprite when shallow copy is used.
Let's look at sf::Sprite::setTexture reference:
The texture argument refers to a texture that must exist as long as
the sprite uses it. Indeed, the sprite doesn't store its own copy of
the texture, but rather keeps a pointer to the one that you passed to
this function. If the source texture is destroyed and the sprite tries
to use it, the behavior is undefined.
So, a class like below, with default generated copy operation by compiler:
class Foo {
public:
void setT() {
// generate texture {t}
s.setTexture(t);
}
sf::Sprite s;
sf::Texture t;
};
will bring troubles to you. Because when a copy is made by Foo f(otherFoo);, sprite in newly created instance of Foo will have pointer to texture of otherFoo - it is shallow copy of pointer to sf::Texture. Deleting otherFoo will make a dangle pointer inside new constructed object.
In this case, you should implement assignment operation which makes deep copy of texture for sprite. If you don't know how to do it, you should mark assignment operations as deleted:
class Character : public sf::Drawable {
public:
Character();
Character(std::string name);
~Character();
// added
Character& operator=(const Character&) = delete;
Character(const Character&) = delete;
void Move(float value);
Then, compiler will give you an error for each attempt of copying of Character instance.
In case of deleted copy operation, you should rely on pointers. Your attempt failed, because you store pointer to local variables. Local variables are deleted at the end of a function scope, and referring to them later is undefined behaviour.
You have to create Character by operator new:
void CharacterManager::CreateCharacter(std::string name, std::string textureFilename, CharacterType characterType, sf::Vector2f pos) {
Character* new_character = new Character(name); // Create a generic character...
//...
// Set texture, position and add to the characters list
new_character->SetTexture(textureFilename);
new_character->SetPosition(pos);
m_characters.insert({ name, new_character });
}
Historically, I've been using trait classes to hold information and apply that into a "generic" function that runs the same "algorithm." Only differed by the trait class. For example: https://onlinegdb.com/ryUo7WRmN
enum selector { SELECTOR1, SELECTOR2, SELECTOR3, };
// declaration
template < selector T> struct example_trait;
template<> struct example_trait<SELECTOR1> {
static constexpr size_t member_var = 3;
static size_t do_something() { return 0; }
};
template<> struct example_trait<SELECTOR2> {
static constexpr size_t member_var = 5;
static size_t do_something() { return 0; }
};
// pretend this is doing something useful but common
template < selector T, typename TT = example_trait<T> >
void function() {
std::cout << TT::member_var << std::endl;
std::cout << TT::do_something() << std::endl;
}
int main()
{
function<SELECTOR1>();
function<SELECTOR2>();
return 0;
}
I'm not sure how to create "generic" algorithms this when dealing with polymorphic classes.
For example: https://onlinegdb.com/S1hFLGC7V
Below I have created an inherited class hierarchy. In this example I have a base catch-all example that defaults all the parameters to something (0 in this case). And then each derived class sets overrides specific methods.
#include <iostream>
#include <memory>
#include <type_traits>
#include <assert.h>
using namespace std;
struct Base {
virtual int get_thing_one() {
return 0;
}
virtual int get_thing_two() {
return 0;
}
virtual int get_thing_three() {
return 0;
}
virtual int get_thing_four() {
return 0;
}
};
struct A : public Base {
virtual int get_thing_one() override {
return 1;
}
virtual int get_thing_three() override {
return 3;
}
};
struct B : public Base {
virtual int get_thing_one() override {
return 2;
}
virtual int get_thing_four() override{
return 4;
}
};
Here I created a simple factory, not elegant but for illustrative purposes
// example simple factory
std::shared_ptr<Base> get_class(const int input) {
switch(input)
{
case 0:
return std::shared_ptr<Base>(std::make_shared<A>());
break;
case 1:
return std::shared_ptr<Base>(std::make_shared<B>());
break;
default:
assert(false);
break;
}
}
So this is the class of interest. It is a class does "something" with the data from the classes above. The methods below are a simple addition example but imagine a more complicated algorithm that is very similar for every method.
// class that uses the shared_ptr
class setter {
private:
std::shared_ptr<Base> l_ptr;
public:
setter(const std::shared_ptr<Base>& input):l_ptr(input)
{}
int get_thing_a()
{
return l_ptr->get_thing_one() + l_ptr->get_thing_two();
}
int get_thing_b()
{
return l_ptr->get_thing_three() + l_ptr->get_thing_four();
}
};
int main()
{
constexpr int select = 0;
std::shared_ptr<Base> example = get_class(select);
setter l_setter(example);
std::cout << l_setter.get_thing_a() << std::endl;
std::cout << l_setter.get_thing_b() << std::endl;
return 0;
}
How can I make the "boilerplate" inside the setter class more generic? I can't use traits as I did in the example above because I can't tie static functions with an object. So is there a way to make the boilerplate example more common?
Somewhere along the lines of having a selector, say
enum thing_select { THINGA, THINGB, };
template < thing_select T >
struct thing_traits;
template <>
struct thing_traits<THINGA>
{
static int first_function() --> somehow tied to shared_ptr<Base> 'thing_one' method
static int second_function() --> somehow tied to shared_ptr<Base> 'thing_two' method
}
template <>
struct thing_traits<THINGB>
{
static int first_function() --> somehow tied to shared_ptr<Base> 'thing_three' method
static int second_function() --> somehow tied to shared_ptr<Base> 'thing_four' method
}
// generic function I'd like to create
template < thing_select T, typename TT = thing_traits<T> >
int perform_action(...)
{
return TT::first_function(..) + TT::second_function(..);
}
I ideally would like to modify the class above to something along the lines of
// Inside setter class further above
int get_thing_a()
{
return perform_action<THINGA>(...);
}
int get_thing_b()
{
return perform_action<THINGB>(...);
}
The answer is, maybe I can't, and I need to pass int the shared_ptr as a parameter and call the specific methods I need instead of trying to tie a shared_ptr method to a static function (in hindsight, that doesn't sound like a good idea...but I wanted to bounce my idea)
Whoever makes the actual call will need a reference of the object, one way or the other. Therefore, assuming you want perform_action to perform the actual call, you will have to pass the parameter.
Now, if you really want to store which function of Base to call as a static in thing_traits without passing a parameter, you can leverage pointer to member functions:
template <>
struct thing_traits<THINGA>
{
static constexpr int (Base::*first_function)() = &Base::get_thing_one;
...
}
template < thing_select T, typename TT = thing_traits<T>>
int perform_action(Base & b)
{
return (b.*TT::first_function)() + ...;
}
You can also play instead with returning a function object that does the call for you (and the inner function takes the parameter).
It all depends on who you need to make the call and what information/dependencies you assume you have available in each class/template.
There are several good answers like this that offer a concise random-only application, but I'm having trouble expanding from that to a small part of a larger application.
Here's what I'm doing:
#include <random>
class RandomFP16
{
public:
static RandomFP16* GetInstance();
int GetRandom();
private:
static RandomFP16* singleton;
RandomFP16();
std::mt19937 mt;
std::uniform_int_distribution<int> dist;
};
RandomFP16* RandomFP16::GetInstance()
{
if(singleton == 0)
{
singleton = new RandomFP16();
}
return singleton;
}
RandomFP16::RandomFP16()
{
std::random_device rd;
//next two lines have errors
mt(rd());
dist(0x00000000, 0x00010000); //fixed-point 16.16
}
int RandomFP16::GetRandom()
{
return dist(mt);
}
So basically, I want one shared random generator that can be used anywhere anytime...at random. :-) Coming from embedded C and Windows C#, I see some strange syntax being used here, so I'm not sure how to structure things to get rid of these errors:
error: no match for call to '(std::mt19937 {aka std::mersenne_twister_engine<unsigned int, 32u, 624u, 397u, 31u, 2567483615u, 11u, 4294967295u, 7u, 2636928640u, 15u, 4022730752u, 18u, 1812433253u>}) (std::random_device::result_type)'
mt(rd());
^
.
error: no match for call to '(std::uniform_int_distribution<int>) (int, int)'
dist(0x00000000, 0x00010000);
^
Okay, I got it. Posting anyway to save someone some work.
#include <random>
class RandomFP16
{
public:
static RandomFP16* GetInstance();
int GetRandom();
private:
static RandomFP16* singleton;
RandomFP16(std::random_device::result_type seed);
std::mt19937 mt;
std::uniform_int_distribution<int> dist;
};
RandomFP16* RandomFP16::singleton = 0;
RandomFP16* RandomFP16::GetInstance()
{
if(singleton == 0)
{
std::random_device rd;
singleton = new RandomFP16(rd());
}
return singleton;
}
RandomFP16::RandomFP16(std::random_device::result_type seed)
: mt(seed), dist(0x00000000, 0x00010000) //fixed-point 16.16
{
}
int RandomFP16::GetRandom()
{
return dist(mt);
}
Turns out the class definition was right; the problems were all in the implentation:
The static variable needs to be declared again outside the class definition. (no idea why)
Local variables (not pointers) with constructors must be initialized like this.
That added an argument to this constructor, which then had to be fed from GetInstance()
I want to use expression templates to create a tree of objects that persists across statement. Building the tree initially involves some computations with the Eigen linear algebra library. The persistent expression template will have additional methods to compute other quantities by traversing the tree in different ways (but I'm not there yet).
To avoid problems with temporaries going out of scope, subexpression objects are managed through std::unique_ptr. As the expression tree is built, the pointers should be propagated upwards so that holding the pointer for the root object ensures all objects are kept alive. The situation is complicated by the fact that Eigen creates expression templates holding references to temporaries that go out of scope at the end of the statement, so all Eigen expressions must be evaluated while the tree is being constructed.
Below is a scaled-down implementation that seems to work when the val type is an object holding an integer, but with the Matrix type it crashes while constructing the output_xpr object. The reason for the crash seems to be that Eigen's matrix product expression template (Eigen::GeneralProduct) gets corrupted before it is used. However, none of the destructors either of my own expression objects or of GeneralProduct seems to get called before the crash happens, and valgrind doesn't detect any invalid memory accesses.
Any help will be much appreciated! I'd also appreciate comments on my use of move constructors together with static inheritance, maybe the problem is there somewhere.
#include <iostream>
#include <memory>
#include <Eigen/Core>
typedef Eigen::MatrixXi val;
// expression_ptr and derived_ptr: contain unique pointers
// to the actual expression objects
template<class Derived>
struct expression_ptr {
Derived &&transfer_cast() && {
return std::move(static_cast<Derived &&>(*this));
}
};
template<class A>
struct derived_ptr : public expression_ptr<derived_ptr<A>> {
derived_ptr(std::unique_ptr<A> &&p) : ptr_(std::move(p)) {}
derived_ptr(derived_ptr<A> &&o) : ptr_(std::move(o.ptr_)) {}
auto operator()() const {
return (*ptr_)();
}
private:
std::unique_ptr<A> ptr_;
};
// value_xpr, product_xpr and output_xpr: expression templates
// doing the actual work
template<class A>
struct value_xpr {
value_xpr(const A &v) : value_(v) {}
const A &operator()() const {
return value_;
}
private:
const A &value_;
};
template<class A,class B>
struct product_xpr {
product_xpr(expression_ptr<derived_ptr<A>> &&a, expression_ptr<derived_ptr<B>> &&b) :
a_(std::move(a).transfer_cast()), b_(std::move(b).transfer_cast()) {
}
auto operator()() const {
return a_() * b_();
}
private:
derived_ptr<A> a_;
derived_ptr<B> b_;
};
// Top-level expression with a matrix to hold the completely
// evaluated output of the Eigen calculations
template<class A>
struct output_xpr {
output_xpr(expression_ptr<derived_ptr<A>> &&a) :
a_(std::move(a).transfer_cast()), result_(a_()) {}
const val &operator()() const {
return result_;
}
private:
derived_ptr<A> a_;
val result_;
};
// helper functions to create the expressions
template<class A>
derived_ptr<value_xpr<A>> input(const A &a) {
return derived_ptr<value_xpr<A>>(std::make_unique<value_xpr<A>>(a));
}
template<class A,class B>
derived_ptr<product_xpr<A,B>> operator*(expression_ptr<derived_ptr<A>> &&a, expression_ptr<derived_ptr<B>> &&b) {
return derived_ptr<product_xpr<A,B>>(std::make_unique<product_xpr<A,B>>(std::move(a).transfer_cast(), std::move(b).transfer_cast()));
}
template<class A>
derived_ptr<output_xpr<A>> eval(expression_ptr<derived_ptr<A>> &&a) {
return derived_ptr<output_xpr<A>>(std::make_unique<output_xpr<A>>(std::move(a).transfer_cast()));
}
int main() {
Eigen::MatrixXi mat(2, 2);
mat << 1, 1, 0, 1;
val one(mat), two(mat);
auto xpr = eval(input(one) * input(two));
std::cout << xpr() << std::endl;
return 0;
}
Your problem appears to be that you are using someone else's expression templates, and storing the result in an auto.
(This happens in product_xpr<A>::operator(), where you call *, which if I read it right, is an Eigen multiplication that uses expression templates).
Expression templates are often designed to presume the entire expression will occur on a single line, and it will end with a sink type (like a matrix) that causes the expression template to be evaluated.
In your case, you have a*b expression template, which is then used to construct an expression template return value, which you later evaluate. The lifetime of temporaries passed to * in a*b are going to be over by the time you reach the sink type (matrix), which violates what the expression templates expect.
I am struggling to come up with a solution to ensure that all temporary objects have their lifetime extended. One thought I had was some kind of continuation passing style, where instead of calling:
Matrix m = (a*b);
you do
auto x = { do (a*b) pass that to (cast to matrix) }
replace
auto operator()() const {
return a_() * b_();
}
with
template<class F>
auto operator()(F&& f) const {
return std::forward<F>(f)(a_() * b_());
}
where the "next step' is passed to each sub-expression. This gets trickier with binary expressions, in that you have to ensure that the evaluation of the first expression calls code that causes the second sub expression to be evaluated, and then the two expressions are combined, all in the same long recursive call stack.
I am not proficient enough in continuation passing style to untangle this knot completely, but it is somewhat popular in the functional programming world.
Another approach would be to flatten your tree into a tuple of optionals, then construct each optional in the tree using a fancy operator(), and manually hook up the arguments that way. Basically do manual memory management of the intermediate values. This will work if the Eigen expression templates are either move-aware or do not have any self-pointers, so that moving at the point of construction doesn't break things. Writing that would be challenging.
Continuation passing style, suggested by Yakk, solves the problem and isn't too insane (not more insane than template metaprogramming in general anyhow). The double lambda evaluation for the arguments of binary expressions can be tucked away in a helper function, see binary_cont in the code below. For reference, and since it's not entirely trivial, I'm posting the fixed code here.
If somebody understands why I had to put a const qualifier on the F type in binary_cont, please let me know.
#include <iostream>
#include <memory>
#include <Eigen/Core>
typedef Eigen::MatrixXi val;
// expression_ptr and derived_ptr: contain unique pointers
// to the actual expression objects
template<class Derived>
struct expression_ptr {
Derived &&transfer_cast() && {
return std::move(static_cast<Derived &&>(*this));
}
};
template<class A>
struct derived_ptr : public expression_ptr<derived_ptr<A>> {
derived_ptr(std::unique_ptr<A> &&p) : ptr_(std::move(p)) {}
derived_ptr(derived_ptr<A> &&o) = default;
auto operator()() const {
return (*ptr_)();
}
template<class F>
auto operator()(F &&f) const {
return (*ptr_)(std::forward<F>(f));
}
private:
std::unique_ptr<A> ptr_;
};
template<class A,class B,class F>
auto binary_cont(const derived_ptr<A> &a_, const derived_ptr<B> &b_, const F &&f) {
return a_([&b_, f = std::forward<const F>(f)] (auto &&a) {
return b_([a = std::forward<decltype(a)>(a), f = std::forward<const F>(f)] (auto &&b) {
return std::forward<const F>(f)(std::forward<decltype(a)>(a), std::forward<decltype(b)>(b));
});
});
}
// value_xpr, product_xpr and output_xpr: expression templates
// doing the actual work
template<class A>
struct value_xpr {
value_xpr(const A &v) : value_(v) {}
template<class F>
auto operator()(F &&f) const {
return std::forward<F>(f)(value_);
}
private:
const A &value_;
};
template<class A,class B>
struct product_xpr {
product_xpr(expression_ptr<derived_ptr<A>> &&a, expression_ptr<derived_ptr<B>> &&b) :
a_(std::move(a).transfer_cast()), b_(std::move(b).transfer_cast()) {
}
template<class F>
auto operator()(F &&f) const {
return binary_cont(a_, b_,
[f = std::forward<F>(f)] (auto &&a, auto &&b) {
return f(std::forward<decltype(a)>(a) * std::forward<decltype(b)>(b));
});
}
private:
derived_ptr<A> a_;
derived_ptr<B> b_;
};
template<class A>
struct output_xpr {
output_xpr(expression_ptr<derived_ptr<A>> &&a) :
a_(std::move(a).transfer_cast()) {
a_([this] (auto &&x) { this->result_ = x; });
}
const val &operator()() const {
return result_;
}
private:
derived_ptr<A> a_;
val result_;
};
// helper functions to create the expressions
template<class A>
derived_ptr<value_xpr<A>> input(const A &a) {
return derived_ptr<value_xpr<A>>(std::make_unique<value_xpr<A>>(a));
}
template<class A,class B>
derived_ptr<product_xpr<A,B>> operator*(expression_ptr<derived_ptr<A>> &&a, expression_ptr<derived_ptr<B>> &&b) {
return derived_ptr<product_xpr<A,B>>(std::make_unique<product_xpr<A,B>>(std::move(a).transfer_cast(), std::move(b).transfer_cast()));
}
template<class A>
derived_ptr<output_xpr<A>> eval(expression_ptr<derived_ptr<A>> &&a) {
return derived_ptr<output_xpr<A>>(std::make_unique<output_xpr<A>>(std::move(a).transfer_cast()));
}
int main() {
Eigen::MatrixXi mat(2, 2);
mat << 1, 1, 0, 1;
val one(mat), two(mat), three(mat);
auto xpr = eval(input(one) * input(two) * input(one) * input(two));
std::cout << xpr() << std::endl;
return 0;
}
I am using QGraphicsScene/QGraphicsView pair in my project
I have performance issue with this pair.
I added my custom graphics items to scene and displayed the contents with view. After that my custom graphics items paint method continuously called by scene(just like infinite loop). This makes %25 of CPU usage(approximately 400 items on scene). What may cause this behaviour?
Here is one my item implementation:
class LevelCrossingItem : public QGraphicsWidget
{
public:
LevelCrossingItem(QString _id,qreal _x,qreal _y);
~LevelCrossingItem();
QRectF boundingRect() const;
QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget /* = 0 */);
void readStateBits();
bool isClosed();
bool isGateArmBroken();
bool isOpenedDuringRouteTanzimCompleted();
bool hasDataConsistencyWarning();
int type() const {return Type;}
private slots:
void setVisible(bool);
private:
enum {Type = FIELDLEVELCROSSING};
QString m_id;
QString m_source;
short m_closedState;
short m_brokenGateArmState;
short m_openedDuringRouteTanzimCompletedState;
short m_dataConsistencyWarningState;
QBitArray stateBitArray;
qreal x,y;
QSvgRenderer *renderer;
};
#include "levelcrossing.h"
LevelCrossingItem::LevelCrossingItem(QString _id,qreal _x,qreal _y):m_id(_id),x(_x),y(_y),stateBitArray(4)
{
m_source = LEVELCROSSING_RESOURCE_PATH.arg("open");
renderer = new QSvgRenderer;
setStateArray(stateBitArray);
setZValue(-0.5);
}
LevelCrossingItem::~LevelCrossingItem()
{
delete renderer;
}
void LevelCrossingItem::setVisible(bool visible)
{
QGraphicsItem::setVisible(visible);
}
QRectF LevelCrossingItem::boundingRect() const
{
return QRectF(QPointF(x,y),sizeHint(Qt::PreferredSize));
}
QSizeF LevelCrossingItem::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
return QSizeF(50,270);
}
void LevelCrossingItem::readStateBits()
{
m_closedState = property("Closed").toInt();
m_brokenGateArmState = property("Broken").toInt();
m_openedDuringRouteTanzimCompletedState = property("OpenedOnRouteWarning").toInt();
m_dataConsistencyWarningState = property("DataConsistencyWarning").toInt();
stateBitArray.setBit(0,qvariant_cast<bool>(m_closedState));
stateBitArray.setBit(1,qvariant_cast<bool>(m_brokenGateArmState));
stateBitArray.setBit(2,qvariant_cast<bool>(m_openedDuringRouteTanzimCompletedState));
stateBitArray.setBit(3,qvariant_cast<bool>(m_dataConsistencyWarningState));
setStateArray(stateBitArray);
}
void LevelCrossingItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget )
{
Q_UNUSED(option);
Q_UNUSED(widget);
readStateBits();
m_closedState == Positive ? m_source = LEVELCROSSING_RESOURCE_PATH.arg("closed")
: m_source = LEVELCROSSING_RESOURCE_PATH.arg("open");
m_brokenGateArmState == Positive ? m_source = LEVELCROSSING_RESOURCE_PATH.arg("broken")
: m_source = m_source;
if(m_openedDuringRouteTanzimCompletedState == Positive)
{
setWarningVisible(OOR_WRN.arg(name()).arg(interlockingRegionId()),true);
if(stateChanged())
emit itemAlarmOccured(m_id,LevelCrossingIsOpenDuringTanzimCompleted);
}
else
setWarningVisible(OOR_WRN.arg(name()).arg(interlockingRegionId()),false);
if(m_dataConsistencyWarningState == Positive)
{
setWarningVisible(DC_WRN.arg(name()).arg(interlockingRegionId()),true);
if(stateChanged())
emit itemAlarmOccured(m_id,LevelCrossingDataConsistency);
}
else
setWarningVisible(DC_WRN.arg(name()).arg(interlockingRegionId()),false);
renderer->load(m_source);
renderer->render(painter,boundingRect());
}
bool LevelCrossingItem::isClosed()
{
return m_closedState == Positive;
}
bool LevelCrossingItem::isGateArmBroken()
{
return m_brokenGateArmState == Positive;
}
bool LevelCrossingItem::isOpenedDuringRouteTanzimCompleted()
{
return m_openedDuringRouteTanzimCompletedState == Positive;
}
bool LevelCrossingItem::hasDataConsistencyWarning()
{
return m_dataConsistencyWarningState == Positive;
}
I read x and y coordinates from xml file. For this item x and y coordinates are 239,344 respectively
Most likely your graphics item has mistakes in the implementation. I had similar behavior, but I was unable to figure out what exactly causes it. I suspect that this happens when you draw outside of the bounding rect. This triggers some clean up routine, which in turn causes redraw of the item, and here goes the loop. Eventually I resolved the issue by carefully inspecting the implementation of my custom graphics item and making sure that:
These is no painting outside of the MyGraphicsItem::boundingRect. Use painter->setClipRect(boundingRect())
MyGraphicsItem::shape does not cross with the MyGraphicsItem::boundingRect.
If you override any other QGraphicsItem functions, make sure that your implementation is correct.
Hope this helps. Feel free to post the source code of your graphics item, it will be easier to find the problem.