• Advertisement

Juliean

GDNet+ Basic
  • Content count

    1648
  • Joined

  • Last visited

Community Reputation

7089 Excellent

About Juliean

  • Rank
    Contributor

Personal Information

Recent Profile Visitors

29248 profile views
  1. C++ use class

    You're trying to assing something to the class-type "FontHandle". MichaelNS::FontHandle handle = m.drawString(FontInfo_t, color, 1600, 660, 1, "FPLN\n");
  2. Running x86 build crashes

    Its part of the Windows SDK, so you should probably have it installed already. Otherwise, here is a direct download: https://www.microsoft.com/en-us/download/details.aspx?id=20028 I can't give you the technical reason, sorry. Had it happen multiple times similarly to what you describe though. Alright, then thats out of the way.
  3. Running x86 build crashes

    Did you really make sure thats the exact line where the data is corrupt? You should make sure that its valid every step of the way (ie. before the method is called) until that very line. If thats really sure and with: Eigther you do have any kind of memory corruption at a firmer point as I suggested, then the only thing you can do is figure that one out. As an alternative possible explanation, did you try a full clean-build & recompile? Seeing as this is a template method, if you modified it somewhere along the lines, there's some issue in VS2017 that sometimes won't recompile the template-method properly. It will then procceed to use some older variant of the code, while showing you the variables and all, possibly resulting in the random garbage you get to see. I had stuff like this happen multiple time in template-heavy code, which was fixed by a recompile. Otherwise, use Application Verifier on your programm (just turn it on for the exe and then run the debugger with Basics->Heaps checked). Does this result in a crash/break at some other point in the code?
  4. Also, some notes for improval on this very method: std::vector<SDL_Rect*> ObstacleManager::getCollisionRectVector() { std::vector<SDL_Rect*> collisionRects; collisionRects.reserve(m_Pillars.size()); // #1 for(auto* pillar : m_Pillars) // #2 { collisionRects.push_back(pillar->getCollisionRect()); } return collisionRects; } #1: You should always call reserve on a vector if you know how many elements you are going to put in, since otherwise you'll have unnecessary allocations/copies. Its a great optimization with little overhead if applied globally. #2: If possible, you should use this "range-based for loop" style over manual index-counting (C++11 required). Its less to type/easier to read and harder to mess up.
  5. Running x86 build crashes

    Not sure if thats already been suggested or tested, but this totally sounds like a memory-misaccess happening at some earlier point, resulting at a crash later with a corrupted call stack. Try the usual tools for finding heap-corruptions (ie. microsoft application verifier) or turn on the debug pageheap (https://stackoverflow.com/questions/2470131/visual-studio-how-to-find-source-of-heap-corruption-errors) if all else fails.
  6. C++ Win32 Clang c++98 vs c++11

    The standard int-types in stdint.h are an C++11 feature. If you want to use them for C++98, you have to define them yourself. What is the value of __cplusplus? You should be able to view/output it to see whats going wrong. Even so, it seems that clang rather uses a check for each indivdual feature instead (https://stackoverflow.com/questions/7139323/what-macro-does-clang-define-to-announce-c11-mode-if-any).
  7. Running x86 build crashes

    Did you check the call stack that is shown with your minidump? That seems to point to a very concrete location, and should probably allow you to spot the error (which seems to relate to eigther vector pushback or your ModelPart-move-ctor).
  8. Nested namespaces useless typing?

    Note that in C++17, there is a feature actually called "nested namespaces", which can make such code way easier to read/write: // might be worth a discussion if this is actually better when there are multiple nested namespaces in one file namespace my::paths { const char *ExtractFileName(const char *path); namespace my::strings { size_t GetAnsiStringLength(const char *str); }; // could instead look like this: namespace my { namespace system::io::path { const char *ExtractFileName(const char *path); }; namespace strings { size_t GetAnsiLength(const char *str); }; }; They are also a better alternative for "smurf naming convention". I worked at a project where every class was prefixed with proj_module_nested_ ... you could argue that this is already an iditiotic naming scheme, but in multi-million line projects, its important to be able to quickly see to which module a certain method/class belongs. I'd actually prefer IO::Paths::GetHome() etc... I tend to group my global methods in a static class instead of a namespace, so I'm just used to seeing multiple levels of nested :: without a problem. I also tend to not using namespace, but instead put all implementations in their respective namespace as well: namespace my::strings { const char* something(const char* path) { IO::Paths::GetHomePath(); // my is implicitely available, as well as my::strings. } } But thats just my sense, in case you want to get some different ideas.
  9. __declspec(selectany)

    Appearently it ensures COMDAT-folding: https://msdn.microsoft.com/en-us/library/5tkz6s71.aspx
  10. Ah, I didn't even notice the alloca. This perfectly explains whats happening here, and I'm even wondering that the compiler isn't optimizing it more aggressively than it already is. Lets recap what you are telling the compiler here: 1: You want some memory off the stack. Unlike _malloca or equivalents, alloca will always be stack based, so the compiler can be sure about that. 2: You are returning a pointer to this memory, which is only valid inside this function. So that tells the compiler that the return-statement, while being able to return the current pointer of the allocation as-is would be valid, the caller of the function would then point to invalid memory, so this should be undefined behaviour. 3: Furthermore, you are not using the destBuffer outside of strncpy-ing to it in the end. Since the compiler can assume that the value of destBuffer is not going to be used after strncpy for return being undefined behaviour, I belive it can optimize it away (at least thats the case for memcpy, so don't hang me if I'm wrong about that). 4. So that means that the compiler is left with an allocation that is literally unused, which means it can probably just remove it (though from what you describe thats not happening, so maybe it is pretenting to allocate, but just generates the address that the allocation would be at, so that i can return *something* at the end?) So maybe thats whats already happening (hard to tell w/o the assembly), but a compiler could just turn that whole code into: If(destBuf != nullptr) // execute function code; return destBuf; else // do nothing return WHATEVER_VALUE. // probably eigther garbage or a pointer along the stack where the allocation would start I'm no expert on compilers but I'm pretty sure thats exactly whats happening. The compiler usually is not allowed to alter the visible behaviour of the program, unless you are, as in your case, relying on undefined behaviour - so the lesson is, never invoke undefined behaviour
  11. In your original code, "destLen" isn't used outside of assignment and the assert though, so the compiler will totally optimize that away. It should still enter the branch and assign the destBuffer though, are you sure that didn't happen as well?
  12. The closest I found was "EditCondition", which allows you to control whether a property can be edited, but requires a separate boolean UPROPERTY: https://wiki.unrealengine.com/UPROPERTY#EditCondition You might want to check the whole list on that wiki-page though, maybe I overlooked something - if what you want exist, it should show up there.
  13. Ah, thats much nicer than my solution, even after I simplified it a bit I'll just have to modify it a bit, as I also need to collapse all tuples recursively - so std::tuple<int, std::tuple<bool, void>, float> becomes std::tuple<int, bool, float>. Thats currently done by this monstrosity: namespace impl { template<typename... Args> struct MergeTuple { }; template<typename... Args, typename... Args2> struct MergeTuple<std::tuple<Args...>, std::tuple<Args2...>> { using type = std::tuple<Args..., Args2...>; }; template<typename... Args> using MergeTupleType = typename MergeTuple<Args...>::type; template<typename... Args> struct ConcatTupleHelper { using type = std::tuple<Args...>; }; template<typename... Types> using ConcatTupleTypes = typename ConcatTupleHelper<Types...>::type; template<typename Arg> struct ConcatTupleHelper<Arg> { using type = std::tuple<Arg>; }; template<typename... Args> struct ConcatTupleHelper<std::tuple<Args...>> { using type = ConcatTupleTypes<Args...>; }; template<typename... Args, typename... Args2> struct ConcatTupleHelper<std::tuple<Args...>, std::tuple<Args2...>> { using type = ConcatTupleTypes<Args..., Args2...>; }; template<typename Arg, typename Arg2, typename... Args> struct ConcatTupleHelper<Arg, Arg2, Args...> { using type = MergeTupleType<ConcatTupleTypes<Arg>, ConcatTupleTypes<Arg2, Args...>>; }; } template<typename... Types> using ConcatTupleTypes = impl::ConcatTupleTypes<Types...>; But I'm sure it will be easier with your code
  14. Uh, nevermind, found a solution (at least for removing the void from tuple): // concat-tuple => constructs one tuple of various elements, tuples, ... namespace impl { template<typename... Args> struct ConcatTupleHelper { }; template<typename... Args, typename... Args2> struct ConcatTupleHelper<std::tuple<Args...>, std::tuple<Args2...>> { using type = std::tuple<Args..., Args2...>; }; template<typename Arg, typename Arg2> struct ConcatTupleHelper<Arg, Arg2> { using type = std::tuple<Arg, Arg2>; }; template<typename Arg, typename... Args> struct ConcatTupleHelper<Arg, std::tuple<Args...>> { using type = std::tuple<Arg, Args...>; }; template<typename... Args, typename Arg> struct ConcatTupleHelper<std::tuple<Args...>, Arg> { using type = std::tuple<Args..., Arg>; }; } template<typename... Types> using ConcatTupleTypes = typename impl::ConcatTupleHelper<Types...>::type; // StripTuple -> removes void from the tuple, using ConcatTupleTypes namespace impl { template<typename Arg> struct StripTuple { using type = Arg; }; template<typename Arg> using StripTupleType = typename StripTuple<Arg>::type; template<> struct StripTuple<std::tuple<void>> { using type = std::tuple<>; }; template<typename Arg, typename Arg2, typename... Args> struct StripTuple<std::tuple<Arg, Arg2, Args...>> { using type = sys::ConcatTupleTypes<Arg, StripTupleType<std::tuple<Arg2, Args...>>>; }; template<typename Arg2, typename... Args> struct StripTuple<std::tuple<void, Arg2, Args...>> { using type = StripTupleType<std::tuple<Arg2, Args...>>; }; } ´ template<typename Arg> using StripTupleType = impl::StripTupleType; Damn, thats a lot of boilerplate-code though, all of which is needed from my testings. Well, if someone still wants to wrap their head around the underlying algorithmn & propose some better alternative, I'm all for it
  15. So what I want to do sounds pretty simple, but I just can't figure it out: I want to remove all types with a certain characteristic from a tuple. For this example, the condition is actually simple: I want to strip all occurances of "void", so std std::tuple<bool, void, int, void, void, float, void>; becomes: std::tuple<bool, int, float>; I ususally don't have a problem with crazy template-code, but this is just above me. I mean, I know how to split the tuple-declaration into elements, but cannot figure out how to just remove one element while leaving the others intact: template<typename Arg> struct StripTuple { using Type = Arg; }; template<typename Arg, typename... Args> struct StripTuple<std::tuple<Arg, Args...>> { using type = std::tuple<Arg, Args...>>; // ignores StripTuple for all other call; call to StripTuple would be infinite recursion }; template<typename... Args> struct StripTuple<std::tuple<void, Args...>> { using type = StripTuple<Args... >>; }; Any simple solutions (remove-condition = void can be used; doesn't have to work with SFINEA if it doesn't need to)? Alternatively, and to give some context, I'd also be happy not to buld the tuple to have voids to begin with. Though I also can't seem to figure that out for the life of me, and I actually belive it would make the code even more complex than just splitting it into two steps, but let me describe the problem (but beware, if you have a solution that works on the requirements above post this before, as I think the actual problem might be hard to get across for me): For my script-function binding, I recently refactored the type-system to handle types with a specializable trait class, which ie. can be defined for value-types: template<typename Type> struct AttributeSupplier<Type, sys::EnableIf<core::IsTypeSystemType<Type> && !core::IsObject<Type>, void>> { static Type GetAttribute(core::ConstVariableView value) { return value.GetValue<Type>(); } static core::TypeId GetTypeId(void) { return core::generateTypeId<Type>(); } }; The important thing about it, which leads to my "problem", is that this works recursively - when the trait is used, it will unfold the argument-list of the "GetAttributes"-method and forward the aquisition to the next AttributeSupplier. As with GetTypeId, this can be omitted, in which case it will do the same thing - aquire the type-id by unfolding the argument-list and checking those types' suppliers. So what the code that requires stripping the tuple of voids does, is try to access the underlying type of any type(s) it receives, by performing the type-unfolding. Thats necessary for multiple reason, for once the type-system can define a runtime-specific value (ie. EntityHandle which is aquired via EntityID), so the underlying type should be "EntityID". Also, to simplify parsing of a function-declaration, this should allow me to pack all argument-type-ids into a single tuple, unfolding all types (which can also include pair/tuple itself). Stripping the void is for system-supplied values - those do not have a type-id, even after unfolding the entire chain of types, so for the UnderlyingType-definition, they need to be removed. So ie., for a function-signature "void f(int, Entity&, DeltaTime, std::pair<float, bool>)", this should result in the tuple-type "std::tuple<int, Entity&, float, bool>". which is done with this code: struct UnderlyingTypeHelper { using InvalidType = void; template<typename Arg, typename Enable = void> struct Helper { }; // helper for recursion template<typename Arg> using HelperType = typename Helper<Arg>::type; private: // if the arguments trait defines a type-id, we're done template<typename Arg> struct Helper<Arg, sys::EnableIf<HasAttributeTypeId<Arg>, void>> { using type = Arg; }; // values not useable as attributes are meant to be removed/set to void template<typename Arg> struct Helper<Arg, sys::EnableIf<!CanBeAttribute<Arg>, void>> { using type = InvalidType; // !!! here's the out to "void" => this would need to somehow not make it into the tuple created below }; // forwarded type-id => container-structs, runtime-mapped values template<typename Arg> struct Helper<Arg, sys::EnableIf<!IsTuple<Arg> && CanBeAttribute<Arg> && !HasAttributeTypeId<Arg>, void>> { using type = HelperType<AttributeFunctionArgs<Arg>>; }; // tuple => unfold function arguments template<typename... Args> struct Helper<std::tuple<Args...>> { using type = std::tuple<HelperType<Args>...>; }; }; The last specialization is responsible for building the output-tuple, while the others are for eigther recursively unfolding the arguments (AttributeFunctionArgs stores the GetAttribute-signature as a tuple), and selecting when to stop with a type-id-supplied Arg, or just "void" out if we reach a point where Arg is not a valid attribute anymore. So yeah, here's some context, and if anyone feels like torturing their brain around some stupid template-code and comes up with a ingenious solution to that, I wouldn't be unhappy. But I doubt that happens, so a solution to the problem stated way above is already more then enough. Thanks
  • Advertisement