Salut, je stocke le pointeur this, dans une classe et ensuite je le copie.
Comme ceci :
struct Test {
Test() {
fd = FastDelegate<void> (&Test::f, this);
fd();
}
void f () {
std::cout<<"calling function f"<<std::endl;
}
FastDelegate<void> fd;
};
int main(int argc, char* argv[]) {
Test test;
}
Et dans la classe FastDelegate je le copie :
namespace odfaeg {
namespace core {
template <size_t I, typename T>
struct placeholder {
using type = T;
static constexpr std::size_t index = I;
};
template<class T, class U>
struct ArgType
{
using type = T;
};
template<class T, class U>
struct ArgType<T, std::reference_wrapper<U>>
{
using type = U&;
};
template<class T, std::size_t I, class U>
struct ArgType<T, placeholder<I, U>>
{
using type = placeholder<I, U>;
};
template<class T>
using ArgType_t = typename ArgType<T, std::remove_cv_t<T>>::type;
//Classe de trait pour déterminer le type à stocker
//(Interne) Cas général
/**
* \file fastDelegate.h
* \class ToStoreImpl
* \param T the type of the wrapper.
* \brief Trait class which use an alias on a wrapped type.
* \author Duroisin.L
* \version 1.0
* \date 1/02/2014
*/
template<class T>
struct ToStoreImpl
{ using type = T; };
/**
* \file fastDelegate.h
* \class ToStoreImpl
* \param T the type warpped in the warpper.
* \brief Trait class with keep an alias on the wrapped type.
* This class is specialized for std::_reference_wrapper type.
* \author Duroisin.L
* \version 1.0
* \date 1/02/2014
*/
template<class T>
struct ToStoreImpl<std::reference_wrapper<T>>
{ using type = T; };
template<size_t I, class T>
struct ToStoreImpl<placeholder<I,T>>
{ using type = T; };
/**
* \file fastDelegate.h
* \class ToStore
* \param T the type of the wrapper.
* \brief Trait class with keep an alias of the wrapper type. (without the reference)
* the inheritance use the right specialized templated class to hold the type of the wrapped object
* depending on the wrapper type.
* \author Duroisin.L
* \version 1.0
* \date 1/02/2014
*/
template<class T>
struct ToStore
: ToStoreImpl<std::remove_reference_t<T>>
{};
/**
* \file fastDelegate.h
* \class ToStore_t
* \param T the type of the wrapped object.
* \brief Trait class which hold an alias to the real type of the wrapped type.
* \author Duroisin.L
* \version 1.0
* \date 1/02/2014
*/
template<class T>
using ToStore_t = typename
ToStore<T>::type;
template<class R, class C, class... ArgT>
struct DynamicWrapper {
/**\fn DynamicWrapper(R(C::*pf)(ArgT...)) : pfunc(pf)
* \brief warp a pointer to a member function.
* \param R(C::*pf)(ArgT...) : the pointer to the member function.
*/
DynamicWrapper(R(C::*pf)(ArgT...)) : pfunc(pf){}
/**\fn R operator()(O* o, ArgU&&... arg) const
* \brief call the member function's pointer witht he given object and the given argument
* apply a dynamic_cast in case of the type of the object and the type of the classe containing the member function
* are not the same. (If the object is polymoprhic)
* If the cast fails it means that the object is not polymorphic so it throws an error.
* \param O* o : the object onwich to call the member function's pointer.
* \param ArgU&& arg : the arguments of the member function's pointer to call.
*/
template<class O, class... ArgU>
R operator()(O* o, ArgU&&... arg) const
{
std::cout<<"class : "<<typeid(C).name()<<std::endl<<"object derived : "<<typeid(*o).name()<<std::endl<<"address : "<<o<<std::endl;
if (o != nullptr) {
if(dynamic_cast<C*>(o))
return (dynamic_cast<C*>(o)->*pfunc)(std::forward<ArgU>(arg)...);
throw std::runtime_error("Invalid cast : types are nor polymorphic!");
}
}
private:
R (C::*pfunc)(ArgT...); /**> a pointer to a member's function.*/
};
/**
* \file fastDelegate.h
* \class DynamicFunction
* \param F the type of the function.
* \brief Generic class for every functors type.
* \author Duroisin.L
* \version 1.0
* \date 1/02/2014
*/
template<class F>
class DynamicFunction;
/**
* \file fastDelegate.h
* \class DynamicFunction
* \param R the return type of the function.
* \param ArgT... the type of the arguments of the function.
* \brief Specialized template class for functors. (inherit from std::function)
* build a functor with the right constructor depending a the pointer's function type.
* \author Duroisin.L
* \version 1.0
* \date 1/02/2014
*/
template<class R, class... ArgT>
class DynamicFunction<R(ArgT...)>
: std::function<R(ArgT...)>
{
/**> just an alias to the type of the base class.*/
using Base = std::function<R(ArgT...)>;
public:
/**
* \fn DynamicFunction(F&& f)
* \brief pass a functor to the std::function.
* \param F&& f : the functor to pass to the std::function.
*/
template<class F>
DynamicFunction(F&& f) : Base(std::forward<F>(f))
{}
/** \fn DynamicFunction (R (C::*pf)(ArgU...))
* \brief pass a pointer to a member's function to the DynamicWrapper, and then
* pass this wrapper to the std::function, so, the std::function call the operator() of the DynamicWrapper class
* and not the operator() of the std::function class so we can perform the dynamic_cast if necessary.
* \param R(C::*pf)(ArgU...) : the pointer to the member's function.
* \
*/
template<class C, class... ArgU>
DynamicFunction(R(C::*pf)(ArgU...))
: Base(DynamicWrapper<R,C,ArgU...>(pf))
{}
/**> just an allias to the operator() of the base class.*/
using Base::operator();
};
template<class F, class... ArgT>
struct DelegateStorage {
/** \fn FastDelegateImpl(F&& f, ArgU&&... arg)
* \brief constructor : create the delegate with the functor and the arguments value passed.
*/
F func;
using TupleArgs = std::tuple<ArgT...>;
TupleArgs params;
};
template<std::size_t i, class T>
struct Parameter
{
T value;
};
template<class... Placeholders>
struct LateParameters : Parameter<Placeholders::index, typename Placeholders::type>... {
static void deleter(void * self)
{
delete static_cast<LateParameters*>(self);
}
};
template<class T, class Params>
T&& get_arg(T&& x, Params& params)
{
std::cout<<"arg : "<<typeid(x).name()<<std::endl<<"arddress : "<<&x<<std::endl;
return static_cast<T&&>(x);
}
template <size_t I, class T, class Params>
T& get_arg(placeholder<I, T>&, Params& params) {
return static_cast<Parameter<I, T>&>(params).value;
}
template<class T>
struct is_placeholder
: std::false_type
{};
template<std::size_t I, class T>
struct is_placeholder<placeholder<I, T>>
: std::true_type
{};
struct LessPlaceceholder
{
template<class PlaceHolder1, class PlaceHolder2>
using f = std::bool_constant<PlaceHolder1::index < PlaceHolder2::index>;
};
template<class R>
struct FastDelegate {
FastDelegate() = default;
template <typename F, typename... Args>
FastDelegate(F&& f, Args&&... args)
: data([&]{
namespace mp = jln::mp;
using late_params_t
= mp::copy_if<mp::lift<is_placeholder>,
mp::unique<mp::sort<LessPlaceceholder,
mp::lift<LateParameters>>>>
::f<std::remove_cv_t<Args>...>;
using storage_t = DelegateStorage<DynamicFunction<R(ToStore_t<Args>&...)>, ArgType_t<Args>...>;
auto delegate = [](Data& data) mutable {
auto& storage = *static_cast<storage_t*>(data.storage);
auto& params = *static_cast<late_params_t*>(data.params);
return std::apply([&](auto&... xs){
return storage.func(get_arg(xs, params)...);
}, storage.params);
};
auto storage_deleter = [](void * storage){
delete static_cast<storage_t*>(storage);
};
DynamicFunction<R(ToStore_t<Args>&...)> df(f);
return Data {
delegate,
storage_deleter,
&late_params_t::deleter,
new storage_t{
static_cast<DynamicFunction<R(ToStore_t<Args>&...)>&&>(df),
typename storage_t::TupleArgs{static_cast<Args&&>(args)...}
},
nullptr,
sizeof(storage_t),
0
};
}())
{}
FastDelegate(FastDelegate& rhs)
: data([&]{
void* tab1 = new char[rhs.data.storage_size];
memcpy(tab1, rhs.data.storage, rhs.data.storage_size);
void* tab2 = nullptr;
if (rhs.data.params != nullptr) {
tab2 = new char[rhs.data.params_size];
memcpy(tab2, rhs.data.params, rhs.data.params_size);
}
//std::cout<<"tab 1 : "<<tab1<<std::endl<<"rhs data.storage : "<<rhs.data.storage<<std::endl;
return Data {
rhs.data.delegate,
rhs.data.storage_deleter,
rhs.data.params_deleter,
tab1,
tab2,
rhs.data.storage_size,
rhs.data.params_size
};
}())
{
//std::cout<<"data.storage : "<<sizeof(data.storage)<<std::endl<<"rhs data.storage : "<<sizeof(rhs.data.storage)<<std::endl;
}
/**\fn FastDelegate (const FastDelegate& rhs)
* \brief copy constructor.
* \param const FastDelegate& rhs : the delegate to copy.
*/
FastDelegate(const FastDelegate& rhs)
: data([&]{
void* tab1 = new char[rhs.data.storage_size];
memcpy(tab1, rhs.data.storage, rhs.data.storage_size);
void* tab2 = nullptr;
if (rhs.data.params != nullptr) {
tab2 = new char[rhs.data.params_size];
memcpy(tab2, rhs.data.params, rhs.data.params_size);
}
return Data {
rhs.data.delegate,
rhs.data.storage_deleter,
rhs.data.params_deleter,
tab1,
tab2,
rhs.data.storage_size,
rhs.data.params_size
};
}())
{
//std::cout<<"copied from const!"<<data.storage<<std::endl<<rhs.data.storage<<std::endl;
}
/**\fn FastDelegate (FastDelegate& rhs)
* \brief move constructor.
* \param FastDelegate&& rhs : the delegate to move.
*/
FastDelegate(FastDelegate&& rhs) =default;
/**\fn FastDelegate& operator= (FastDelegate& rhs)
* \brief affect the content of the delegate to the delegate.
* \param const FastDelegate& rhs : the delegate affect.
* \return FastDelegate& : the affected delegate.
*/
FastDelegate& operator=(const FastDelegate& rhs)
{
void* tab1 = new char[rhs.data.storage_size];
memcpy(tab1, rhs.data.storage, rhs.data.storage_size);
void* tab2 = nullptr;
if (rhs.data.params != nullptr) {
tab2 = new char[rhs.data.params_size];
memcpy(tab2, rhs.data.params, rhs.data.params_size);
}
data.delegate = rhs.data.delegate;
data.storage_deleter = rhs.data.storage_deleter;
data.params_deleter = rhs.data.params_deleter;
/*data.storage_deleter(data.storage);
data.params_deleter(data.params);*/
data.storage = tab1;
data.params = tab2;
data.storage_size = rhs.data.storage_size;
data.params_size = rhs.data.params_size;
//std::cout<<"operator = !"<<std::endl;
return *this;
}
/**\fn FastDelegate& operator= (FastDelegate& rhs)
* \brief affect and move the content of the delegate to the delegate.
* \param const FastDelegate& rhs : the delegate to move and to affect.
* \return FastDelegate& : the moved and affected delegate.
*/
FastDelegate& operator=(FastDelegate&&) =default;
template<typename... Args>
bind(Args&&... args) {
bind_impl(std::index_sequence_for<Args...>(), static_cast<Args&&>(args)...);
}
template<typename... Args>
setParams(Args&&... args) {
using storage_t = DelegateStorage<DynamicFunction<R(ToStore_t<Args>&...)>, ArgType_t<Args>...>;
auto& storage = *static_cast<storage_t*>(data.storage);
data.storage = new storage_t{static_cast<DynamicFunction<R(ToStore_t<Args>&...)>&&>(storage.func), typename storage_t::TupleArgs{static_cast<Args&&>(args)...}};
}
R operator()() {
return data.delegate(data);
}
~FastDelegate()
{
data.params_deleter(data.params);
data.storage_deleter(data.storage);
}
private :
template<std::size_t... Ints, class... Args>
void bind_impl(std::index_sequence<Ints...>, Args&&... args)
{
assert(!data.params);
using params_t = LateParameters<placeholder<Ints, ArgType_t<Args>>...>;
if (¶ms_t::deleter == data.params_deleter) {
data.params = new params_t{static_cast<Args&&>(args)...};
data.params_size = sizeof(params_t);
}
else {
throw std::runtime_error("bad parameter(s)");
}
}
struct Data
{
R (*delegate)(Data&);
void (*storage_deleter)(void*);
void (*params_deleter)(void*);
void * storage;
void * params;
size_t storage_size;
size_t params_size;
};
Data data;
};
}
}
Oui ce code est complexe néanmoins je ne vois pas ce qu'il y a de différent entre le pointeur this et un autre pointeur à part le fait que le pointeur this pointe sur l'objet courant, j'ai l'impression que le pointeur this change d'adresse et quand ça arrive ça plante car ce n'est plus le bon objet mais pourtant avec mon ancienne implémentation, cela fonctionne et avec le constructeur de copie également à mon avis c'est parce que je fais un return *this; que ça plante..., je vais essayer de changer cela mais si je ne sais pas pourquoi ça plante je vais devoir revenir à l'ancienne implémentation mais mon but c'est de comprendre mieux ce language est de persévérer parce que pour l'instant j'ai du mal avec les notions plus avancées et j'ai du mal à implémenter une solution moi même même si je comprends quand on me donne la solution.
Quand on arrive à la méta programmation, les lambdas expressions et les void* précisément je galère. Il m'arrive souvent de manipuler du code que je ne comprends pas. Cet solution utilisé les trois points que j'ai le plus de mal à comprendre.
mp::copy, sort et tout ça je ne sais pas comment ça marche.
Et au niveau de la correspondance des types des paramètres template j'ai du mal aussi avec les classes de traits, bref, j'avais lu des tutoriels mais c'est tellement loin et le fichier mp.h est trop volumineux pour comprendre surtout pour un débutant je pense qu'il y a moyen de faire ça plus simplement mais je ne vois pas comment je serai incapable d'implémenter ça moi même.
Sur développer.com avec mon ancienne implémentation j'ai eu des explications et quand ça ne fonctionnait pas on m'expliquait mais ici, ce n'est pas la même chose quand quelqu'un me propose une solution et que ça plante pas de solution comme si la personne ne comprenais pas le code qu'elle me donne et parfois la solution est tellement bête que je la trouve moi même.., mais pas de réponses à part des critiques.
Alors on voit tout de suite les personnes expertes comme celui qui m'a montré l'ancienne implémentation et les personnes novices qui donne un code sans le comprendre ou quand je poste un code on ne le comprend pas.
EDIT : Il faut avouer que la syntaxe du c++ moderne n'est pas évidente je crois pas qu'on sache voir le code généré par les template comme avec le préprocesseur.
Oui, mais je redemande, pourquoi as tu besoin de faire cela ?
Est ce que c'est un exercice ? Tu cherches à faire le truc le plus fou possible ?
Ce n'est pas parce que le C++ moderne propose plein d'outils qu'il faut les utiliser n'importe quand de n'importe quelle façon !
Déjà, normalement un gars qui programme avec des lambda, des template et des classes de traits comme tu dis, c'est un "moderne", et il a abandonné les pointeurs, et surtout les void* !
Mêler les deux, c'est mêler deux mondes qui ne devraient pas cohabiter.
Ou alors on se la fait en C, void* et taille, et basta, memcpy et c'est plié, ça me va aussi !
Etre bon en C++, ce n'est pas faire les choses les plus compliquées possibles.
Il faut penser à maintenir le code !
Je suis dans le monde professionnel depuis 17 ans, et le mec qui me fait ça au boulot, c'est la peine de mort... minimum !
Si on bricole, et que tu me dis :
"regarde, cette pointe je la mets dans le mur, je mets 3 équerres, un gyroscope, des tasseaux, je fais une entaille à la scie électrique, je sors une perceuse à visée laser, je...."
- tu veux faire quoi ?
- mettre un cadre ! bien droit !
- ben moi je prends un niveau à bulle, 2 clous et c'est plié...
Essaie de nous définir une fois pour toutes quelle est ton besoin. Concrètement. Et va droit au but !
Ok, le problème est bien celui auquel je pense : l'adresse du pointeur this n'est pas la même dans la classe Test et dans la classe FastDelegate, elle change!
La question que je me pose maintenant c'est pourquoi ?
La valeur du pointeur this est 0x4a3ff4 mais dans la classe FastDelegate elle prend une valeur bizarre qui est 0xfeefee
Et le pire c'est que ça ne me le fait pas tout le temps. (comportement indéterminé)
Il appelle le constructeur ici et pas l'opérateur= ni le constructeur de copie je me demande si c'est normal.
Bref, je ne comprend pas pourquoi ça plante donc je ne saurai pas résoudre ce problème.
template<class R>
struct FastDelegate {
FastDelegate() = default;
template <typename F, typename... Args>
FastDelegate(F&& f, Args&&... args)
: data([&]{
namespace mp = jln::mp;
using late_params_t
= mp::copy_if<mp::lift<is_placeholder>,
mp::unique<mp::sort<LessPlaceceholder,
mp::lift<LateParameters>>>>
::f<std::remove_cv_t<Args>...>;
using storage_t = DelegateStorage<DynamicFunction<R(ToStore_t<Args>&...)>, ArgType_t<Args>...>;
auto delegate = [](Data& data) mutable {
auto& storage = *static_cast<storage_t*>(data.storage);
auto& params = *static_cast<late_params_t*>(data.params);
return std::apply([&](auto&... xs){
return storage.func(get_arg(xs, params)...);
}, storage.params);
};
auto storage_deleter = [](void * storage){
delete static_cast<storage_t*>(storage);
};
DynamicFunction<R(ToStore_t<Args>&...)> df(f);
return Data {
delegate,
storage_deleter,
&late_params_t::deleter,
new storage_t{
static_cast<DynamicFunction<R(ToStore_t<Args>&...)>&&>(df),
typename storage_t::TupleArgs{static_cast<Args&&>(args)...}
},
nullptr,
sizeof(storage_t),
0
};
}())
{
std::cout<<"constructor"<<std::endl;
}
FastDelegate(FastDelegate& rhs)
: data([&]{
void* tab1 = new char[rhs.data.storage_size];
memcpy(tab1, rhs.data.storage, rhs.data.storage_size);
void* tab2 = nullptr;
if (rhs.data.params != nullptr) {
tab2 = new char[rhs.data.params_size];
memcpy(tab2, rhs.data.params, rhs.data.params_size);
}
return Data {
rhs.data.delegate,
rhs.data.storage_deleter,
rhs.data.params_deleter,
tab1,
tab2,
rhs.data.storage_size,
rhs.data.params_size
};
}())
{
std::cout<<"copy constructor"<<std::endl;
}
/**\fn FastDelegate (const FastDelegate& rhs)
* \brief copy constructor.
* \param const FastDelegate& rhs : the delegate to copy.
*/
FastDelegate(const FastDelegate& rhs)
: data([&]{
void* tab1 = new char[rhs.data.storage_size];
memcpy(tab1, rhs.data.storage, rhs.data.storage_size);
void* tab2 = nullptr;
if (rhs.data.params != nullptr) {
tab2 = new char[rhs.data.params_size];
memcpy(tab2, rhs.data.params, rhs.data.params_size);
}
return Data {
rhs.data.delegate,
rhs.data.storage_deleter,
rhs.data.params_deleter,
tab1,
tab2,
rhs.data.storage_size,
rhs.data.params_size
};
}())
{
std::cout<<"copy constructor (const)"<<std::endl;
}
/**\fn FastDelegate (FastDelegate& rhs)
* \brief move constructor.
* \param FastDelegate&& rhs : the delegate to move.
*/
FastDelegate(FastDelegate&& rhs) =default;
/**\fn FastDelegate& operator= (FastDelegate& rhs)
* \brief affect the content of the delegate to the delegate.
* \param const FastDelegate& rhs : the delegate affect.
* \return FastDelegate& : the affected delegate.
*/
FastDelegate& operator=(const FastDelegate& rhs)
{
/*void* tab1 = new char[rhs.data.storage_size];
memcpy(tab1, rhs.data.storage, rhs.data.storage_size);
void* tab2 = nullptr;
if (rhs.data.params != nullptr) {
tab2 = new char[rhs.data.params_size];
memcpy(tab2, rhs.data.params, rhs.data.params_size);
}
data.delegate = rhs.data.delegate;
data.storage_deleter = rhs.data.storage_deleter;
data.params_deleter = rhs.data.params_deleter;
data.storage = tab1;
data.params = tab2;
data.storage_size = rhs.data.storage_size;
data.params_size = rhs.data.params_size;
//std::cout<<"operator = !"<<std::endl;
return *this;*/
std::cout<<"operation affector"<<std::endl;
return operator=(FastDelegate(rhs));
}
/**\fn FastDelegate& operator= (FastDelegate& rhs)
* \brief affect and move the content of the delegate to the delegate.
* \param const FastDelegate& rhs : the delegate to move and to affect.
* \return FastDelegate& : the moved and affected delegate.
*/
FastDelegate& operator=(FastDelegate&&) =default;
template<typename... Args>
bind(Args&&... args) {
bind_impl(std::index_sequence_for<Args...>(), static_cast<Args&&>(args)...);
}
template<typename... Args>
setParams(Args&&... args) {
using storage_t = DelegateStorage<DynamicFunction<R(ToStore_t<Args>&...)>, ArgType_t<Args>...>;
auto& storage = *static_cast<storage_t*>(data.storage);
data.storage = new storage_t{static_cast<DynamicFunction<R(ToStore_t<Args>&...)>&&>(storage.func), typename storage_t::TupleArgs{static_cast<Args&&>(args)...}};
}
template<typename... Args>
R operator()(Args&&... args) {
using storage_t = DelegateStorage<DynamicFunction<R(ToStore_t<Args>&...)>, ArgType_t<Args>...>;
auto& storage = *static_cast<storage_t*>(data.storage);
display_params(std::index_sequence_for<Args...>(), storage.params);
return data.delegate(data);
}
~FastDelegate()
{
data.params_deleter(data.params);
data.storage_deleter(data.storage);
}
private :
template<std::size_t... Ints, class... Args>
void display_params(std::index_sequence<Ints...>, std::tuple<Args...> args) {
printf("%s%x%s", "value of this in delegate : ", std::get<Ints>(args)..., "\n");
}
template<std::size_t... Ints, class... Args>
void bind_impl(std::index_sequence<Ints...>, Args&&... args)
{
assert(!data.params);
using params_t = LateParameters<placeholder<Ints, ArgType_t<Args>>...>;
if (¶ms_t::deleter == data.params_deleter) {
data.params = new params_t{static_cast<Args&&>(args)...};
data.params_size = sizeof(params_t);
}
else {
throw std::runtime_error("bad parameter(s)");
}
}
struct Data
{
R (*delegate)(Data&);
void (*storage_deleter)(void*);
void (*params_deleter)(void*);
void * storage;
void * params;
size_t storage_size;
size_t params_size;
};
Data data;
};
struct Test {
Test() {
std::cout<<"this pointer value in class Test : "<<this<<std::endl;
fd = FastDelegate<void> (&Test::f, this);
fd(this);
}
void f () {
std::cout<<"calling function f"<<std::endl;
}
FastDelegate<void> fd;
};
int main(int argc, char* argv[]) {
Test test;
return 0;
}
Avec l'ancienne implémentation je n'ai pas ce problème mais je la stocke dans une structure Val et puis RefVal avant de la passer au tuple, ce que jo_link ne fait pas parce que qu'il m'a dit qu'il n'y a pas besoin d'héritage pour faire ça!!!
Enfin bref, voilà une image qui illustre le problème : (peut être c'est parce que jo_link la stocke dans un tuple et que le tuple prend une référence ?)
Si oui, comment copier les éléments dans le tuple plutôt que de les référencer ?
Vous avez donc vraisemblablement pris un objet qui c'est fait "libéré" en DEBUG, avant que la mémoire ne se fasse recyclée.
>Et le pire c'est que ça ne me le fait pas tout le temps. (comportement indéterminé)
Chez ceux que tu n'écoutes pas, on appelle ça une UB (https://en.cppreference.com/w/cpp/language/ub ), c'est pas faute de t'avoir prévenu de ne pas faire n'importe quoi, juste parce que ça à l'air de fonctionner, les nuits de pleine lune, dans un pentacle fait de sang de poulet fraîchement égorgé, par une brise du Sud-Sud/Est.
>Il appelle le constructeur ici
C'est quelle ligne le "ici" ???
>Bref, je ne comprend pas pourquoi ça plante
Bin, utilisez le débogueur pour qu'il vous informe quand la valeur change vers une valeur incorrecte, c'est tout.
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
Vous avez donc vraisemblablement pris un objet qui c'est fait "libéré" en DEBUG, avant que la mémoire ne se fasse recyclée.
>Et le pire c'est que ça ne me le fait pas tout le temps. (comportement indéterminé)
Chez ceux que tu n'écoutes pas, on appelle ça une UB (https://en.cppreference.com/w/cpp/language/ub ), c'est pas faute de t'avoir prévenu de ne pas faire n'importe quoi, juste parce que ça à l'air de fonctionner, les nuits de pleine lune, dans un pentacle fait de sang de poulet fraîchement égorgé, par une brise du Sud-Sud/Est.
>Il appelle le constructeur ici
C'est quelle ligne le "ici" ???
>Bref, je ne comprend pas pourquoi ça plante
Bin, utilisez le débogueur pour qu'il vous informe quand la valeur change vers une valeur incorrecte, c'est tout.
0xfeefee ou 0xfeeefeee ???
Oui il faudrait que je regarde quand la valeur change et prend une valeur incorrecte, ça me le fait aussi en release car ça plante aussi en release dans certains cas de figure.
Je crois qu'il détruit Coin{this}; après l'avoir passé à l'opérateur=, mais le problème ne vient pas de là parce que j'ai mit le code du destructeur en commentaire et ça plante encore. (plus le code que j'ai présenté plus haut mais, celui-ci : )
Bref, je pense que je vais repasser à l'ancienne implémentation de ma classe FastDelegate.
J'ai des cas parfois ça marche, parfois ça marche pas et je sais pas trop pourquoi ça plante, déjà le type affiché à l'exécution avec typeid n'est pas le même avec la nouvelle et l'ancienne implémentation, avec la nouvelle implémentation ça m'affiche le type d'un objet qui ne possède pas la fonction membre (ODFAEGCreator*) et avec l'ancienne le bon type (MenuItem) à l'appel de l'opérateur= dans DynamicWrapper, donc déjà là le type à l'exécution n'est pas bon dans certains cas.
J'utilise tdm-gcc32 bits et comme option de compilation j'ai -std=cpp17 et -g en debug sinon -O2 et -s en release.
Par contre il y a moulte d'erreurs sous vs :
Gravité Code Description Projet Fichier Ligne État de la suppression
Erreur C1903 impossible de récupérer à partir des erreurs précédentes ; arrêt de la compilation odfaeg-graphics C:\Users\Laurent\Windows\ODFAEG\include\odfaeg\Core\mp.hpp 13698 Erreur C1083 Impossible d'ouvrir le fichier include : 'dirent.h' : No such file or directory odfaeg-core C:\Users\Laurent\Windows\ODFAEG\include\odfaeg\Core\utilities.h 8
Erreur C2397 la conversion de 'size_t' en 'jln::mp::int_' requiert une conversion restrictive odfaeg-core C:\Users\Laurent\Windows\ODFAEG\include\odfaeg\Core\mp.hpp 11811
Erreur C2397 la conversion de 'size_t' en 'jln::mp::int_' requiert une conversion restrictive odfaeg-core C:\Users\Laurent\Windows\ODFAEG\include\odfaeg\Core\mp.hpp 11819
Erreur C2065 'typed_value' : identificateur non déclaré odfaeg-core C:\Users\Laurent\Windows\ODFAEG\include\odfaeg\Core\mp.hpp 13311
Erreur C2059 erreur de syntaxe : 'decltype' odfaeg-core C:\Users\Laurent\Windows\ODFAEG\include\odfaeg\Core\mp.hpp 13311
Erreur C2653 'x' : n'est pas un nom de classe ni d'espace de noms odfaeg-core C:\Users\Laurent\Windows\ODFAEG\include\odfaeg\Core\mp.hpp 13311
Erreur C2065 'value' : identificateur non déclaré odfaeg-core C:\Users\Laurent\Windows\ODFAEG\include\odfaeg\Core\mp.hpp 13311
Erreur C2062 type 'unknown-type' inattendu odfaeg-core C:\Users\Laurent\Windows\ODFAEG\include\odfaeg\Core\mp.hpp 13311
Erreur C2146 erreur de syntaxe : absence de '>' avant l'identificateur 'type' odfaeg-core C:\Users\Laurent\Windows\ODFAEG\include\odfaeg\Core\mp.hpp 13311
Erreur C2062 type 'unknown-type' inattendu odfaeg-core C:\Users\Laurent\Windows\ODFAEG\include\odfaeg\Core\mp.hpp 13312
Erreur C2143 erreur de syntaxe : absence de ';' avant '}' odfaeg-core C:\Users\Laurent\Windows\ODFAEG\include\odfaeg\Core\mp.hpp 13315
Erreur C2238 jetons inattendus avant ';' odfaeg-core C:\Users\Laurent\Windows\ODFAEG\include\odfaeg\Core\mp.hpp 13315
Erreur C2923 'jln::mp::detail::_one' : 'xs::value' n'est pas un argument de type modèle valide pour le paramètre 'x' odfaeg-core C:\Users\Laurent\Windows\ODFAEG\include\odfaeg\Core\mp.hpp 13335
Erreur C2988 impossible de reconnaître la définition/déclaration de modèle odfaeg-core C:\Users\Laurent\Windows\ODFAEG\include\odfaeg\Core\mp.hpp 13335
TDM-gcc32 est réputé moisi. De mémoire, ca utilise une vieille version de GCC. La doc dit que c'est basé sur C99.
J'ai testé avec GCC et Clang, les calculs sont corrects.
wikipedia a écrit:
MinGW links by default to the Windows OS component library MSVCRT, which is the C library that Visual C++ version 6.0 linked to (the initial target was CRTDLL), which was released in 1998 and therefore does not include support for C99 features, or even all of C89. While targeting MSVCRT yields programs that require no additional runtime redistributables to be installed, the lack of support for C99 has caused porting problems, particularly where printf-style conversion specifiers are concerned. These issues have been partially mitigated by the implementation of a C99 compatibility library, libmingwex, but the extensive work required is far from complete and may never be fully realized.[10]Mingw-w64 has resolved these issues, and provides fully POSIX compliant printf functionality.
Utilise MSVC. Ou mingw64. Mais pas TDM-gcc32.
Ca te pose pas de problème que MSVC te retourne autant d'erreurs ?
TDM-gcc32 est réputé moisi. De mémoire, ca utilise une vieille version de GCC. La doc dit que c'est basé sur C99.
J'ai testé avec GCC et Clang, les calculs sont corrects.
wikipedia a écrit:
MinGW links by default to the Windows OS component library MSVCRT, which is the C library that Visual C++ version 6.0 linked to (the initial target was CRTDLL), which was released in 1998 and therefore does not include support for C99 features, or even all of C89. While targeting MSVCRT yields programs that require no additional runtime redistributables to be installed, the lack of support for C99 has caused porting problems, particularly where printf-style conversion specifiers are concerned. These issues have been partially mitigated by the implementation of a C99 compatibility library, libmingwex, but the extensive work required is far from complete and may never be fully realized.[10]Mingw-w64 has resolved these issues, and provides fully POSIX compliant printf functionality.
Utilise MSVC. Ou mingw64. Mais pas TDM-gcc32.
Ca te pose pas de problème que MSVC te retourne autant d'erreurs ?
- Edité par gbdivers il y a 13 minutes
Si, surtout que je n'ai pas ces erreurs sous mingw, je vais essayer avec mingw ça devrait mieux fonctionner.
J'ai essayé avec mingw-W64 mais le résultat du calcul n'est toujours pas bon, je vais essayer sous visual studio, mais avant, je dois terminer de finir de réimplémenter le fichier mp.h de jonathan qui ne compile pas sous visual studio et je pense qu'il n'est pas bon non plus.
mingw32, mingw64, VS .................... tu vas en essayer combien ????
Et quand tu distribuera ton appli, tu imposera le compilateur aussi ? Ca ne va pas plaire à tous le monde.
Ce n'est pas le compilateur qui est en cause, un code bien pensé compile sur toutes les plateformes, quelque soit le compilateur. La seule contrainte est que la version de C++ utilisée soit supportée par le compilateur.
PS: Le meilleur moyen de tracker une variable, c'est de faire du pas à pas, et mettre des espions.
mingw32, mingw64, VS .................... tu vas en essayer combien ????
Et quand tu distribuera ton appli, tu imposera le compilateur aussi ? Ca ne va pas plaire à tous le monde.
Ce n'est pas le compilateur qui est en cause, un code bien pensé compile sur toutes les plateformes, quelque soit le compilateur. La seule contrainte est que la version de C++ utilisée soit supportée par le compilateur.
PS: Le meilleur moyen de tracker une variable, c'est de faire du pas à pas, et mettre des espions.
Je vais en essayer plusieurs, jusqu'à que j'en trouve un qui compile et exécute le code correctement. (Je vais essayer clang)
Désolé mais je ne peux pas travailler avec des outils qui ne fonctionnent pas donc oui il se peut que j'impose un compilateur.
Comme je t'ai dit dans l'autre discussion, il y a des erreurs dans le code que tu as donné (et que j'ai du corriger pour compiler). Le problème n'est pas que les compilateurs ne fonctionnent pas, c'est que ton code est incorrect.
> Désolé mais je ne peux pas travailler avec des outils qui ne fonctionnent pas donc oui il se peut que j'impose un compilateur.
On en est à du haut niveau de troll, là... GCC (ben oui, mingw32-64 c'est GCC), Clang, et MSVC sont des compilos utilisés dans des dizaines de milliers de projets, t'inquiète pas qu'ils sont éprouvés et qu'ils fonctionnent (ils sont pas exempts de bugs, hein, mais pas du niveau de ce que tu as).
Pour me mettre au même niveau de troll que toi, je pense que tu devrais éviter de travailler avec ton framework
Si vous ne trouvez plus rien, cherchez autre chose.
Est-ce que quelqu'un est en mesure de comprendre ce code ? J'ai l'impression de lire les entrailles d'un header boost...
Tiens voilà pour toi! C'est plus clair ce code ? Il est plus lent que celui de fichier mp.hpp de Jonathan à cause de l'instanciation des std::tuples, mais, moins sal donc moins susceptible de planter, ça résoudra peut être le plantage que j'ai avec la nouvelle implémentation du delegate.
template <size_t SIZE, typename T>
struct placeholder {
static size_t constexpr size = SIZE;
using size_type = size_t;
using type = T;
};
template<class T>
struct is_placeholder
: std::false_type
{};
template<std::size_t I, class T>
struct is_placeholder<placeholder<I, T>>
: std::true_type
{};
template<std::size_t N, typename Seq> struct offset_sequence;
template<std::size_t N, std::size_t... Ints>
struct offset_sequence<N, std::index_sequence<Ints...>>
{
using type = std::index_sequence<Ints + N...>;
};
template<std::size_t N, typename Seq>
using offset_sequence_t = typename offset_sequence<N, Seq>::type;
template <size_t O, size_t N, size_t... Ints>
std::index_sequence<Ints...> make_offset_sequence () {
return offset_sequence_t<O, std::make_index_sequence<N>>::type();
}
template<typename Seq1, typename Seq> struct cat_sequence;
template<std::size_t... Ints1, std::size_t... Ints2>
struct cat_sequence<std::index_sequence<Ints1...>,
std::index_sequence<Ints2...>>
{
using type = std::index_sequence<Ints1..., Ints2...>;
};
template<typename Seq1, typename Seq2>
using cat_sequence_t = typename cat_sequence<Seq1, Seq2>::type;
template<typename T, std::size_t... Ints>
auto select_tuple(std::index_sequence<Ints...>)
{
T tuple;
return std::tuple<T>();
}
template<std::size_t N, typename T>
auto remove_Nth()
{
constexpr auto size = std::tuple_size_v<T>;
using first = std::make_index_sequence<N>;
using rest = offset_sequence_t<N+1,
std::make_index_sequence<size-N-1>>;
using indices = cat_sequence_t<first, rest>;
return select_tuple<T>(indices{});
}
template<template<class> class Pred, template <class...> class R>
struct append_if {
template <size_t I, class T, class... D, class = typename std::enable_if<Pred<decltype(std::get<I>(T()))>::value>::type>
static constexpr auto get() /*-> decltype(push_front<R,A, xs...>::type())*/{
return T();
}
template <size_t I, class T, class = typename std::enable_if<!Pred<decltype(std::get<I>(T()))>::value>::type>
static constexpr auto get() /*-> decltype(R<xs...>())*/ {
return remove_Nth<I, T>();
}
template <size_t I=0, class T, class... D, class = typename std::enable_if<(I == std::tuple_size<T>())>::type>
static constexpr auto f() /*-> decltype(get<decltype(std::get<Ints>(T())())...>())*/ {
return get<I-1, T>();
}
template <size_t I=0, class T, class... D, class... E, class = typename std::enable_if<(I != 0 && I != std::tuple_size<T>())>::type>
static constexpr auto const f() /*-> decltype(get<decltype(std::get<Ints>(T())())...>())*/ {
return get<I-1, T>();
}
template <size_t I=0, class T, class... D, class...E, class... F, class = typename std::enable_if<(I == 0)>::type>
static constexpr auto f() /*-> decltype(f<I+1>(std::make_index_sequence<std::tuple_size<T>()-I>()))*/ {
return f<I+1, T>();
}
};
template<template <class> class Pred, typename T, template <class> class R>
struct copy_if {
using f = decltype(append_if<Pred, R>::template f<0, T>());
};
/*template<class T, template <class> class R>
struct make_unique {
template <typename A, class... xs>
//requires std::derived_from<Pred<A>, std::true_type>
static constexpr auto get() -> decltype(push_front<R,A, xs...>::type()){
return push_front<R,A, xs...>::type();
}
/*template <typename A, class... xs>
requires std::derived_from<Pred<A>, std::false_type>
static constexpr auto get() -> decltype(std::tuple<xs...>()) {
return std::tuple<A, xs...>();
}*/
/*template <size_t I=0, size_t... Ints>
requires (I == std::tuple_size<T>())
static constexpr auto func(std::index_sequence<Ints...>) -> decltype(get<decltype(std::get<Ints+I-1>(T())())...>()) {
return get<decltype(std::get<Ints+I-1>(T())())...>();
}
template <size_t I=0, size_t... Ints>
requires (I > 0 && I != std::tuple_size<T>())
static constexpr auto const func(std::index_sequence<Ints...>) -> decltype(get<decltype(std::get<Ints+I-1>(T())())...>()) {
return get<decltype(std::get<Ints+I-1>(T())())...>();
}
template <size_t I=0, size_t... Ints>
requires (I == 0)
static constexpr auto func(std::index_sequence<Ints...>) -> decltype(func<I+1>(std::make_index_sequence<std::tuple_size<T>()-I>())) {
return func<I+1>(std::make_index_sequence<std::tuple_size<T>()-I>());
}
};
template<class L, template <class> class R>
struct unique {
using f = decltype(make_unique<L, R>::func(std::make_index_sequence<std::tuple_size<L>()-0>()));
};*/
int main(int argc, char* argv[])
{
using late_params_t
= copy_if<is_placeholder,std::tuple<placeholder<3, int>, float, placeholder<2, int>, int, placeholder<1, int>, char, placeholder<0, int>>, std::tuple>::f;
std::cout<<typeid(late_params_t).name()<<std::endl;
return 0;
Mais avant je dois encore faire les fonctions uniques et sort, personnellement j'aime bien ça fait un bon exercice pour l'apprentissage de la méta programmation et moins compliqué que le fichier mp.hpp qui est inaccessible pour ceux qui n'ont jamais fait de méta programmation.
Plantage, copie du pointeur this.
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
Si vous ne trouvez plus rien, cherchez autre chose.
Discord NaN. Mon site.
Discord NaN. Mon site.
Discord NaN. Mon site.
Discord NaN. Mon site.
Si vous ne trouvez plus rien, cherchez autre chose.
git is great because Linus did it, mercurial is better because he didn't.