Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Dr Monkeysee
Oct 11, 2002

just a fox like a hundred thousand others
Nap Ghost
If I have a function that takes a parameter pack simply to pass it on to another function that takes a parameter pack do I pass it on as-is or with std::forward?

Example (template butt calls template poop calls some regular old variadic function):

C++ code:
void some_variadic_function(const char* blah, ...);

template<typename... TParams>
void poop(TParams&&... params)
{
   // textbook use of forwarding here
    some_variadic_function("poopbutt", std::forward<TParams>(params...));
}

// but calling a universal ref function from another universal ref function...

// do i pass them like this?
template<typename... TParams>
void butt(TParams&&... params)
{
    poop(params...);
}


// or like this?
template<typename... TParams>
void butt(TParams&&... params)
{
    poop(std::forward<TParams>(params...));
}
I'm unclear on whether forwarding is required when passing from one universal reference to another, all the examples I can find online only mention the poop -> variadic function step. My *guess* is forwarding is required from butt to poop; even though both functions accept a parameter pack. Without forwarding from butt to poop "r-valueness" would still be lost since the parameter pack expansion into concrete arguments for poop would give r-values names and thus make them l-values.

But I'm not entirely sure. Forwarding and universal references are confusing and I'm concerned there's some hidden side-effect I don't understand.

Dr Monkeysee fucked around with this message at 21:07 on Sep 12, 2016

Adbot
ADBOT LOVES YOU

eth0.n
Jun 1, 2012

Dr Monkeysee posted:

Without forwarding from butt to poop "r-valueness" would still be lost since the parameter pack expansion into concrete arguments for poop would give r-values names and thus make them l-values.

But I'm not entirely sure. Forwarding and universal references are confusing and I'm concerned there's some hidden side-effect I don't understand.

Yes, you are correct. You should use std::forward.

Generally, you should use std::forward unless it's a situation where std::move would not be safe. For example, if you call one function with your parameter, then another. The first one shouldn't get forwarded, since it could invalidate the reference prior to the second call.

Dr Monkeysee
Oct 11, 2002

just a fox like a hundred thousand others
Nap Ghost

eth0.n posted:

For example, if you call one function with your parameter, then another. The first one shouldn't get forwarded, since it could invalidate the reference prior to the second call.

Yeah this case I was able to find online and while it didn't address my problem it was one of those "oh poo poo, I should file that away for later".

This stuff is complicated. I haven't touched c++ since about 2001 and I feel like I end up reading several pages on en.cppreference.com and 3 or 4 stackoverflow threads for every single line of code I'm writing. Maybe I'm over thinking it, but I've learned several languages over the years and c++ is the only one where I'm balancing an entire encyclopedia of semantics in my head just to figure out my own code. I spent about 3 hours this weekend figuring out how template function overloading vs specialization interacted with each other.

Dr Monkeysee fucked around with this message at 21:29 on Sep 12, 2016

Chuu
Sep 11, 2004

Grimey Drawer
Ran into a bug today in the code below. I am passing in a 64-bit number, which is encoding three pieces of information as:|32-bit|16-bit|16bit|. In the code below, routeId should contain the middle 16-bit field, but it does not.

code:
void prepareConnection(uint64_t routingId) {
    const std::uint32_t rs = (std::uint32_t) (std::numeric_limits<uint32_t>::max() & routingId);
    const uint32_t routeId = rs >> 16;
    
    auto &route = m_routes[routeId];
    ...
}
This appears to work in debug builds, but looking at the assembly in release the first line with the "&" mask turns into a no-op and route ends up referencing m_routes[routingId >> 16]. Is this invoking some sort of undefined behavior?

Chuu fucked around with this message at 03:09 on Sep 13, 2016

pseudorandom name
May 6, 2007

Are you sure that's what the assembly shows?

Keep in mind that accessing a 64-bit register as a 32-bit register on AMD64 implicitly zeroes the upper 32-bits.

Chuu
Sep 11, 2004

Grimey Drawer

pseudorandom name posted:

Are you sure that's what the assembly shows?

Keep in mind that accessing a 64-bit register as a 32-bit register on AMD64 implicitly zeroes the upper 32-bits.

Yes, I've spent way more time than I care to admit debugging it, including stepping line by line through the assembly.

Doc Block
Apr 15, 2003
Fun Shoe
It's optimizing away the AND operation since it shouldn't be needed (since the destination variable can't hold the upper 32 bits anyway).

But if it really is just replacing it all with m_routes[routingId >> 16] then I would think that's your problem: you're still getting the other 48 bits of routingId since it never got truncated and the upper 32 bits aren't being zeroed.

Maybe remove the numeric_limits stuff and change the bit shift to const uint32_t routeId = (rs >> 16) & 0xFFFF;

edit: also, why are you doing std::uint32_t in some places but just uint32_t in others?

Chuu
Sep 11, 2004

Grimey Drawer

Doc Block posted:

edit: also, why are you doing std::uint32_t in some places but just uint32_t in others?

I'm not the original author, basically copy-pasting it as close as I can to the original since the specific declarations could be relevant. There are several ways to rewrite this that might "fix" it, but I'm wondering if there is something in the code that is undefined behavior or a bug that's going right over my head.

It's not literally doing rs >> 16, in the assembly it's basically moving rdi to a 64-bit register (r10), doing a shift, and then using it to compute the address of the array element. It's used later on in the method which is probably why it's dedicating a register to it.

Chuu fucked around with this message at 04:19 on Sep 13, 2016

Doc Block
Apr 15, 2003
Fun Shoe
Looks like it's optimizing away the AND operation with uint32_t's max value (since it shouldn't be needed if it really is being converted down to a 32-bit uint), but then optimizes away the 64->32-bit cast/conversion, which leaves the whole upper 32-bits of routingID intact, so when it gets shifted right 16 bits you're essentially getting the entire upper 48 bits of routingID as the array index.

So just make sure to mask out the bits you don't want after the shift.
code:
void prepareConnection(uint64_t routingID)
{
        const uint32_t routeID = (uint32_t)(routingID >> 16) & 0xFFFF;
        auto &route = m_routes[routeID];
        ...
}
What compiler are you using? I couldn't reproduce this behavior with clang (and didn't need the mask afterwards).

Themage
Jul 21, 2010

by Nyc_Tattoo
I've been building a game-boy emulator over the last few days to teach myself c++ and programming in general but I've run into an error trying to read the game-boy bootrom. I open the file and copy its contents into an array called memblock(shown below) but silently fails instead. It used to work before when I passed the array as a function parameter to my CPU's instantiate function but after refactoring it seems to have broke and I'm not sure what I broked :saddowns:.


code:
//main.cpp

#include <iostream>
#include <fstream>
#include <string>
#include "z80cpu.h"

int main() {

	CPU GameboyCPU;

	std::string ROMPath = "";
	std::cout << "Provide a path to a game ROM: ";
	std::cin >> ROMPath;
	GameboyCPU.Cart.LoadROM(ROMPath, 0);
	GameboyCPU.Initialize();

	//runs the first ten instructions
	for (int i = 0; i < 10; i++) {
		GameboyCPU.RunSingleInstruction(GameboyCPU.registers.pc);
	}

	...
	...
	return 0;
}
code:
//z80cpu.h
#pragma once
#include "ram.h"
#include "Rom.h"

struct CPU {
	uint32_t clock = 4194304;
	uint64_t step = 0;
	Memory Ram;
	ROM Cart;
	uint8_t* cartridge;
	...
	...
	void CPU::Initialize();
	void CPU::LDDHL();
	...
}
I define a pointer to the Rom structs memblock here named cartridge but functions like LDDHL seem to have trouble reading from it
code:
//z80cpu.cpp
void CPU::Initialize() {

	//Initialize Ram
	cartridge = Cart.memblock;
	Ram.Initialize();
	...
	...
}
void CPU::LDDHL() {
	uint16_t HL = registers.H << 8 | registers.L;
	//ram[HL] = registers.A;
	Ram.writeRam(HL, registers.A);
	registers.L -= 1;
	registers.pc += 1;
	std::cout << "LDD " << HL << " " << (int)registers.A;
}

The code for reading the rom file(s)
code:
//rom.h
#pragma once
#include <fstream>

struct ROM {
	uint8_t* memblock;
	std::fstream rom;
	std::streampos size;
	int flag;

	void ROM::LoadROM(std::string path, int flag);
	void ROM::BinaryDump(std::string path, std::streampos size);
	void ROM::CloseROM();
};
code:
//rom.cpp
void ROM::LoadROM(std::string path, int flag) {
	try
	{
		this->rom.open(path, std::ios::in | std::ios::binary | std::ios::ate);
	}
	catch (const std::exception&)
	{
		throw std::invalid_argument("Error Opening file");
	}
	
	
	if (rom.is_open()) {
		size = rom.tellg();
		std::cout << "\nThe Rom is " << rom.tellg() << " byte(s) long." << std::endl;
		memblock = new uint8_t[size];
		std::cout << rom.tellg() << " Bytes of memory have been allocated" << std::endl;
		rom.seekg(0, std::ios::beg);
		rom.read(reinterpret_cast<char *>(memblock), size);
		std::cout << "The contents of the file are stored in memory" << std::endl;
		rom.close();
		if (flag == 0) {
		}
		else {
			BinaryDump(path, this->size);
		}
	}
}

	...
	...
Sorry for the huge post but I have no idea what I need to fix this.

csammis
Aug 26, 2003

Mental Institution
Have you tried running this in a debugger, stepping through the LoadROM function to see whether memblock is actually read in correctly?

What was the code pre-refactor? What did the refactor change?

e: What do you mean that "functions like LDDHL" has trouble reading from memblock? Do you mean member functions in general? The LDDHL() function you posted doesn't appear to touch the cartridge member of CPU.

csammis fucked around with this message at 17:59 on Sep 13, 2016

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today
Also, you should really be using std::unique_ptr<uint8_t[]> for ROM::memblock, and probably not keeping the IO handles around if you're reading the whole thing into memory anyway.

Themage
Jul 21, 2010

by Nyc_Tattoo

csammis posted:

Have you tried running this in a debugger, stepping through the LoadROM function to see whether memblock is actually read in correctly?

What was the code pre-refactor? What did the refactor change?

e: What do you mean that "functions like LDDHL" has trouble reading from memblock? Do you mean member functions in general? The LDDHL() function you posted doesn't appear to touch the cartridge member of CPU.

I didnt change anything about the rom loading itself, only the handing off of memblock to the cpu afterwards

I put the full code on github https://github.com/RichFY/GameBoi but heres the code before refactoring
code:
//main.cpp
#include <iostream>
#include <fstream>
#include <string>
#include "z80cpu.h"
#include "ram.h"
#include "Rom.h"

int main() {

	CPU GameboyCPU;
	Memory Ram;
	ROM Cartridge;

	bool bootComplete = false;

	std::string ROMPath = "";
	int dumpFlag = 0; //whether to dump the rom or not
	std::cout << "Provide a path to a game ROM: ";
	std::cin >> ROMPath;
	//std::cout << "\nDo you wish to dump the Rom? 0 = no | 1 = yes" << std::endl;
	//std::cin >> dumpFlag;
	Cartridge.LoadROM(ROMPath, 0);
	GameboyCPU.Initialize(Cartridge.memblock);
	Ram.Initialize();
	GameboyCPU.PrintRegisters();

	
	
	//GameboyCPU.BootROM();

	for (int i = 0; i < 10; i++) {
		GameboyCPU.RunSingleInstruction(Ram.RAM,GameboyCPU.registers.pc);		
	}
	

	std::cout << std::endl;
	Cartridge.CloseROM();
	return 0;
 } 
z80cpu.cpp: https://github.com/RichFY/GameBoi/blob/03bb00053ceae265b95b5ac09e0def21822ea555/z80cpu.cpp

z80cpu.h: https://github.com/RichFY/GameBoi/blob/03bb00053ceae265b95b5ac09e0def21822ea555/z80cpu.h

Themage fucked around with this message at 21:49 on Sep 13, 2016

eth0.n
Jun 1, 2012

Themage posted:

I didnt change anything about the rom loading itself, only the handing off of memblock to the cpu afterwards

I put the full code on github https://github.com/RichFY/GameBoi but heres the code before refactoring

What output are you observing?

Themage
Jul 21, 2010

by Nyc_Tattoo

eth0.n posted:

What output are you observing?

This is the output from loading the bootrom currently


What it should do is print the size of the rom in bytes, print that memory for memblock was allocated and that the rom finished reading into memblock, then it should print the cpu registers like above. From testing memblock gets allocated and filled properly but I cant seem to actually read data from it in z80cpu.cpp

eth0.n
Jun 1, 2012

Themage posted:

This is the output from loading the bootrom currently


What it should do is print the size of the rom in bytes, print that memory for memblock was allocated and that the rom finished reading into memblock, then it should print the cpu registers like above. From testing memblock gets allocated and filled properly but I cant seem to actually read data from it in z80cpu.cpp

Your ROM::LoadROM function has a bunch of prints that don't appear there. How could memblock be correctly allocated and filled if those prints aren't appearing? What makes you think it is?

My guess, the ROM file open is failing for some reason. You should report an error message (or throw an exception) whenever something like that fails, not just silently abort the function.

Themage
Jul 21, 2010

by Nyc_Tattoo
Welp turns out that when I was committing my stuff to github I accidently deleted the bootrom I was using :suicide: on the plus side my code works fine though.

csammis
Aug 26, 2003

Mental Institution
I'd suggest it's not working fine if you could delete a file that's required for correct operation and your program executes without warning about it :)

Cory Parsnipson
Nov 15, 2015
I have a project where I had one huge include file "dependencies.h" that had a bunch of third party and <iostream>, <vector>, etc includes in most of my files. I recently refactored this to get rid of this huge include file and only pull in the dependencies I need per file, figuring it would greatly improve my build time. When I run my program now, I actually see a great increase in framerate and start up time. Is this just a coincidence or has fixing my includes somehow affected my runtime performance?

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today

Cory Parsnipson posted:

I have a project where I had one huge include file "dependencies.h" that had a bunch of third party and <iostream>, <vector>, etc includes in most of my files. I recently refactored this to get rid of this huge include file and only pull in the dependencies I need per file, figuring it would greatly improve my build time. When I run my program now, I actually see a great increase in framerate and start up time. Is this just a coincidence or has fixing my includes somehow affected my runtime performance?
You used version control and can easily test the before/after commits, right?

(spoilers: no, if you did what you said that should have had exactly zero effect, but it's often worth tracking down the real reason for a surprising performance change)

Cory Parsnipson
Nov 15, 2015
Ok so I did move a bunch of files around at the same time... I'll try to see if I can find any leads in the commit logs. Thanks!

raminasi
Jan 25, 2005

a last drink with no ice

Cory Parsnipson posted:

I have a project where I had one huge include file "dependencies.h" that had a bunch of third party and <iostream>, <vector>, etc includes in most of my files. I recently refactored this to get rid of this huge include file and only pull in the dependencies I need per file, figuring it would greatly improve my build time. When I run my program now, I actually see a great increase in framerate and start up time. Is this just a coincidence or has fixing my includes somehow affected my runtime performance?

For the record, if your toolchain supports precompiled headers somehow (it probably does), the way you had it before will be faster, assuming you actually precompile dependencies.h.

Cory Parsnipson
Nov 15, 2015
Nooooooooooo... :negative:

Spatial
Nov 15, 2007

4Ghz six-core CPUs and we still have to worry about build times. That's our C++!

One day he'll grow up and move out of his mother's basement, one day... :shobon:

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today

raminasi posted:

For the record, if your toolchain supports precompiled headers somehow (it probably does), the way you had it before will be faster, assuming you actually precompile dependencies.h.
Faster to build, that is.

raminasi
Jan 25, 2005

a last drink with no ice

Ralith posted:

Faster to build, that is.

Oops yeah, I should have been explicit about that. Shouldn't affect the running time either way.

Joda
Apr 24, 2010

When I'm off, I just like to really let go and have fun, y'know?

Fun Shoe
Is it a new thing in g++ 6.0 that it won't accept std::string() as an argument to a function that expects std::string&?

Xarn
Jun 26, 2015

Joda posted:

Is it a new thing in g++ 6.0 that it won't accept std::string() as an argument to a function that expects std::string&?

No, a non-const ref shouldn't bind to a temporary since forever, because that is almost certainly an error.

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today
If you really want that behavior (if you have to ask, you don't) you use an rvalue reference instead.

Joda
Apr 24, 2010

When I'm off, I just like to really let go and have fun, y'know?

Fun Shoe
Oh no, I don't mind. Needing a const there makes sense, but I'm working on someone else's library and trying to get it working with g++, and I think I'm running into a bunch of errors because MSVC is way too relaxed with these sorts of things.

netcat
Apr 29, 2008
Does that actually work in MSVC? That seems really weird

Joda
Apr 24, 2010

When I'm off, I just like to really let go and have fun, y'know?

Fun Shoe

netcat posted:

Does that actually work in MSVC? That seems really weird

Maybe the guy who wrote it has it set up with whatever the MSVC equivalent of fpermissive is or something, I dunno. Maybe MSVC guesses what you mean and does some under the hood conversions for you? I saw it compile on his system before I started poking in it myself.

Bonfire Lit
Jul 9, 2008

If you're one of the sinners who caused this please unfriend me now.

netcat posted:

Does that actually work in MSVC? That seems really weird
it used to work on g++ too, they changed it in one of the early 4.x I think (I want to say 4.2)

e: MSVC flags it if you use the equivalent to -Wall (/W4)

Bonfire Lit fucked around with this message at 09:00 on Sep 16, 2016

netcat
Apr 29, 2008
Of course I remember VC and older gcc's accepting all kinds of weird stuff so..

Pontificating Ass
Aug 2, 2002

What Doth Life?

rjmccall posted:

I'm not going to write some thousand-word post about C++ reference types for every person who wanders into the thread. Go learn the basics of the language you're trying to use.
Im not looking to argue or anything but you misinterpreted my post and assumed I didn't know how to use a fundamental concept, then misinterpreted it again and assumed I want you to teach me how to use it. I'll stick to my programming for dummies book thank you

Spatial
Nov 15, 2007

Joda posted:

Maybe the guy who wrote it has it set up with whatever the MSVC equivalent of fpermissive is or something, I dunno. Maybe MSVC guesses what you mean and does some under the hood conversions for you? I saw it compile on his system before I started poking in it myself.
MSVC allows stupid things like this by default, and the compiler switch to disable it ("disable language extensions") will break the standard library implementation if you use it. It does warn at level 4 but hardly anyone bothers because it barrages you with non-issues.

Spatial
Nov 15, 2007

Also while I'm complaining about MSVC, lmao that their implementation of deque<T> allocates buckets smaller than a cache line and degrades to a linked list if T is bigger than 64 bits.

Xarn
Jun 26, 2015

Spatial posted:

Also while I'm complaining about MSVC, lmao that their implementation of deque<T> allocates buckets smaller than a cache line and degrades to a linked list if T is bigger than 64 bits.

IIRC, only libc++ has sane deque<T>, libstdc++ also has a predetermined bucket size and then just divides it to elements. There is some scary poo poo in old C++ stdlib implementations.

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed
Not being able to bind an lvalue reference to a temporary was a restriction added fairly late in the standardization process, and it's a rare example of C++ forbidding something because it's a footgun rather than because it can't work.

Adbot
ADBOT LOVES YOU

hackbunny
Jul 22, 2007

I haven't been on SA for years but the person who gave me my previous av as a joke felt guilty for doing so and decided to get me a non-shitty av

Spatial posted:

MSVC allows stupid things like this by default, and the compiler switch to disable it ("disable language extensions") will break the standard library implementation if you use it. It does warn at level 4 but hardly anyone bothers because it barrages you with non-issues.

What version? From what I read, the latest version of the standard library should compile cleanly both with /Za and /W4 (not /Wall though). And you can enable warnings one by one, you don't have to raise the warning level

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply