Initializer_list isnt working...?

Started by
5 comments, last by SmkViper 8 years, 7 months ago

math::Vec2f Font::getLineVerticalBounds() const
		{
			FT_Face face = reinterpret_cast<FT_Face>(mFace);
			return math::Vec2f{ static_cast<float>(face->size->metrics.descender) / 64.0f, static_cast<float>(face->size->metrics.ascender) / 64.0f };
		}

See the "math::Vec2f" right after the return statement?

If it IS there, this works.

If it IS NOT there, a default initialized vector is returned (0,0) (or garbage that happens to be close to 0 idk) where something like (-9,3) is expected.

Here is the initializer_list constructor thingy:


template<class VecType, ui32 ComCnt>
		template<typename T>
		Vector<VecType, ComCnt>::Vector(std::initializer_list<T> values)
		{
			assert(values.size() <= ComCnt);
			auto iter = values.begin();
			for (ui32 i = 0; i < values.size(); ++i) //I checked that size is always 2
			{
				(*this)[i] = static_cast<VecType>(*(iter++));
			}
		}

In debug mode, that initializer_list contains garbage (claims to have 12 elements and all are rubbish)

In release mode its harder to debug.

AND the funny thing is, if I turn optimization off, it works just fine. Sure it STILL returns absolute garbage, but it works...?

Spent the whole day trying to figure out why my FPS indicator magically disappears in release mode with optimizations enabled >.<

Is it even legal to return the arguments wrapped in {} and then having the returned object construct itself from that? I just realized this works fine without the second piece of code being present. edit: I mean legal with the initializer_list based constructor

o3o

Advertisement


math::Vec2f Font::getLineVerticalBounds() const
		{
			FT_Face face = reinterpret_cast<FT_Face>(mFace);
			return math::Vec2f{ static_cast<float>(face->size->metrics.descender) / 64.0f, static_cast<float>(face->size->metrics.ascender) / 64.0f };
		}
See the "math::Vec2f" right after the return statement?

If it IS there, this works.

If it IS NOT there,..


you mean, you're trying that:

math::Vec2f Font::getLineVerticalBounds() const
		{
			FT_Face face = reinterpret_cast<FT_Face>(mFace);
			return static_cast<float>(face->size->metrics.descender) / 64.0f, static_cast<float>(face->size->metrics.ascender) / 64.0f;
		}
?

that is the same as

math::Vec2f Font::getLineVerticalBounds() const
		{
			FT_Face face = reinterpret_cast<FT_Face>(mFace);
			return static_cast<float>(face->size->metrics.ascender) / 64.0f;
		}
math::Vec2f Font::getLineVerticalBounds() const
		{
			FT_Face face = reinterpret_cast<FT_Face>(mFace);
			return { static_cast<float>(face->size->metrics.descender) / 64.0f, static_cast<float>(face->size->metrics.ascender) / 64.0f; }
		}
That's what you want isn't it? Note the curly braces.

um no.

Basically theres 3 things:

1. The presence of the "math::Vec2f" in front of the {} with the components

2. The removal of the 2nd function in my post (a constructor of math::Vec2f, takes an initializer_list)

3. Optimizations being disabled

If I do any one of those, the program works. If I do none of them it breaks. I picked #2.

edit:



math::Vec2f Font::getLineVerticalBounds() const
{
FT_Face face = reinterpret_cast(mFace);
return { static_cast(face->size->metrics.descender) / 64.0f, static_cast(face->size->metrics.ascender) / 64.0f; }
}

That's what you want isn't it? Note the curly braces.

Thats basically what I did (without the math::Vec2f) and it broke the program in release mode. So I added the explicit math::Vec2f there and that worked. After that I figured I should instead just remove the 2nd function because it wasnt necessary and was probably incorrect...

o3o

Using a braced initializer on the return statement without the type should be legal C++. What compiler are you using? What version of said compiler?

Have you stepped through things with the debugger? Checked when things are destructed? Tried printing things out from your various constructors? (Including copy and move constructors, which may be potentially used)

A quick online test shows that it should work fine - so maybe you could try extracting the bug from the rest of your code to see if it still reproduces?

Is the caller of getLineVerticalBounds actually putting the result of the function into a variable by value or is it using a pointer or reference that will point at deleted memory as soon as the return happens?

And an unrelated question: Why are you using a manual for loop? Ranged-for is so much nicer smile.png

Using a braced initializer on the return statement without the type should be legal C++. What compiler are you using? What version of said compiler?

Im using MSVC++ 2015 community edition (version 14? the version number is such long...)

Also Im compiling for 64 bit. And theres templates everywhere.


Have you stepped through things with the debugger? Checked when things are destructed? Tried printing things out from your various constructors? (Including copy and move constructors, which may be potentially used)

For this particular one I just noticed garbage goes in the initializer_list constructor thing, so I got rid of that entirely since I apparently never even needed it in the first place.


A quick online test shows that it should work fine - so maybe you could try extracting the bug from the rest of your code to see if it still reproduces?

I ran your test in visual studio, and it seems like this really is a bug in the compiler - 64 bit with optimizations specifically (doesnt happen in x86 or in debug mode)


And an unrelated question: Why are you using a manual for loop? Ranged-for is so much nicer

It was too overwhelming to try and figure out where to get the current iteration number after writing a billion regular for loops ._.'

If someone else has VS 2015 please reproduce using smkvipers code (compile release/x64) and send them a bug report, the bug reporting mechanism isnt working for me (complains about not enough authorizations)

EDIT:

Using an rvalue reference for the return value (instead of just returning by value) also avoids the bug.

o3o

A quick online test shows that it should work fine - so maybe you could try extracting the bug from the rest of your code to see if it still reproduces?


I ran your test in visual studio, and it seems like this really is a bug in the compiler - 64 bit with optimizations specifically (doesnt happen in x86 or in debug mode)


May be a VS bug, if I was at home I'd have plugged it in and tried there.

And an unrelated question: Why are you using a manual for loop? Ranged-for is so much nicer

It was too overwhelming to try and figure out where to get the current iteration number after writing a billion regular for loops ._.'


True, ranged-for doesn't give you an index. I think actually a std::transform would be ideal to avoid writing a for loop entirely, but I was in a rush and didn't want to hide the loop behind a standard library algorithm on the off chance that the loop itself was causing a bug.

EDIT:
Using an rvalue reference for the return value (instead of just returning by value) also avoids the bug.


I'm pretty sure that places you even more into undefined-behavior land because you are now returning a temporary by reference.

Also, returning an r-value reference doesn't make sense because return values are already R-values at the call site.

This topic is closed to new replies.

Advertisement