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
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
People use SDL2 routinely on x86_64, it works fine. Are you using the cmake build properly? You can probably scrounge prebuilt binaries if you need to, but the build should work fine. Whatever you do don't use mingw, it is bad. One of the best things about Rust for game purposes is first-class Windows (i.e. MSVC) support.

Adbot
ADBOT LOVES YOU

c0burn
Sep 2, 2003

The KKKing
SDL2 gfx is not a part of official SDL.

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
Well that's confusing. Maybe try using a non-dead library instead.

Fergus Mac Roich
Nov 5, 2008

Soiled Meat
Sorry, just got around to this. The library builds on MSVC x64 with MMX disabled. I wasn't able to confirm that functionality is as expected but I don't see any reason to doubt it. Thanks for the advice, folks.

edit: Yep tried it out after I got home from work and it's perfect.

Fergus Mac Roich fucked around with this message at 03:19 on Feb 8, 2018

Colonel J
Jan 3, 2008
I have a bit of a weird question that was inspired by Raymond Chen's latest blog entry.

quote:

The initial implementation of the Bit¬Blt function in 16-bit Windows didn't have any special tricks. It was static code that supported the sixteen raster operations that involve a source and destination.
The second version of Bit¬Blt generated code on the fly. Specifically, the Bit¬Blt function generated code onto the stack which performed the block transfer with the appropriate operation, and then called the code as a subroutine.

... generating code on the stack, on the fly? I'm not sure how that works.

Can you really do something like

code:
    // define an array full of asm instructions on the stack
    char a[] = 
    {
        *some asm instruction*,
        *another asm instruction*,
	... // and so on
    };
    
    // then move the instruction pointer to the list of instructions you just defined
    (&a)();
Now I'm no C wizard and what I wrote doesn't compile, but is this the general idea of it i.e. write raw bytes corresponding to machine code somewhere, somehow move the instruction pointer there and just feed those bytes to the processor?

Thanks a bunch, apologies if this is dumb.

b0lt
Apr 29, 2005

Colonel J posted:

I have a bit of a weird question that was inspired by Raymond Chen's latest blog entry.


... generating code on the stack, on the fly? I'm not sure how that works.

Can you really do something like

code:
    // define an array full of asm instructions on the stack
    char a[] = 
    {
        [i]some asm instruction[/i],
        [i]another asm instruction[/i],
	... // and so on
    };
    
    // then move the instruction pointer to the list of instructions you just defined
    (&a)();
Now I'm no C wizard and what I wrote doesn't compile, but is this the general idea of it i.e. write raw bytes corresponding to machine code somewhere, somehow move the instruction pointer there and just feed those bytes to the processor?

Thanks a bunch, apologies if this is dumb.


Yep, pretty much, except on modern operating systems/processors, you generally can't generate code onto your stack anymore because it's marked no-execute. Nowadays, you have to separately allocate executable pages of memory to generate code into.

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS
You can disable the NX bit on a per-binary basis if you want - it's not set in stone. There are actually some cases where you can get GCC to push some code on the stack if you're clever enough.

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS
See this:
https://stackoverflow.com/questions/8179521/implementation-of-nested-functions

Colonel J
Jan 3, 2008
Huh that's kind of blowing my mind, thanks for your answers. There's always something more to amaze me.

"allocate executable pages of memory" was the keywords I needed, and this stack overflow question shows how to do it in modern C++.

feedmegin
Jul 30, 2008

Colonel J posted:

Somehow move the instruction pointer there and just feed those bytes to the processor?

Thanks a bunch, apologies if this is dumb.

The 'somehow' is just creating a function pointer and setting it to that address then calling it (then your machine code - not asm - follows the appropriate calling convention), yeah.

Star War Sex Parrot
Oct 2, 2003

Colonel J posted:

Huh that's kind of blowing my mind, thanks for your answers. There's always something more to amaze me.

"allocate executable pages of memory" was the keywords I needed, and this stack overflow question shows how to do it in modern C++.
If you want to learn more, here's a lecture (from an intro to computer systems class) that covers things like buffer overflows, stack smashing, and return-oriented programming attacks in C. It also talks a bit about things like NX bit, stack canaries, and other mitigation techniques.

https://www.youtube.com/watch?v=cw5a5I8OoY0

Slides are here:
http://www.cs.cmu.edu/afs/cs/academic/class/15213-f17/www/lectures/09-machine-advanced.pdf

When I took this class, one of the assignments was to actually implement some of these techniques and it was pretty drat cool.

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS

Star War Sex Parrot posted:

If you want to learn more, here's a lecture (from an intro to computer systems class) that covers things like buffer overflows, stack smashing, and return-oriented programming attacks in C. It also talks a bit about things like NX bit, stack canaries, and other mitigation techniques.

<snip>

Slides are here:
http://www.cs.cmu.edu/afs/cs/academic/class/15213-f17/www/lectures/09-machine-advanced.pdf

When I took this class, one of the assignments was to actually implement some of these techniques and it was pretty drat cool.
Did you explode your bomb lab???? I did once, shameful. Always cool to see CMU goons around. I definitely enjoyed implementing buffer overflow code and doubt I'll ever get to do stuff like that again - very cool class. (I wish we did ret-to-libc stuff but I bet that's harder to make a workable assignment for.)

Star War Sex Parrot
Oct 2, 2003

Jeffrey of YOSPOS posted:

Did you explode your bomb lab????
Never :frogc00l:

Jeffrey of YOSPOS posted:

I did once, shameful.
:rip:

Jeffrey of YOSPOS posted:

Always cool to see CMU goons around.
You can't assume that anymore, since my understanding is the course has been adopted at a decent number of campuses now! But yep, I'm here as a grad student.

Bonfire Lit
Jul 9, 2008

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

Colonel J posted:

Can you really do something like
[snip]
Now I'm no C wizard and what I wrote doesn't compile, but is this the general idea of it i.e. write raw bytes corresponding to machine code somewhere, somehow move the instruction pointer there and just feed those bytes to the processor?
This is basically what your OS's binary loader does too: it loads a bunch of machine code from the disk into memory, marks it executable, and then tells the CPU to jump to a special location in the loaded code (the entry point). Also every language that does JIT compiling (i.e. Java, C#, etc) has code in some intermediate language, rewrites it to fit the current CPU's architecture, and then runs it directly, because that's way faster than naively interpreting the bytecode.

Twerk from Home
Jan 17, 2009

This avatar brought to you by the 'save our dead gay forums' foundation.
I have to get a C++ project from 2011 to build, and I'm having a hell of a time. I'd like to be able to just get a working binary out with as little fuss as possible, but right at the entry point in global scope it starts with
code:
using namespace boost;
using namespace std;
which causes pretty much any modern compilers and cstd libs to explode. I guess that when this was originally being developed, the version of boost that was included in the includes directory was synchronized to the stdlib version on the development machine?

Long story short, I've got a ton of ambiguous references, and I'm not even sure where to start. Just remove all "using" statements and be specific about namespace where things are called?

Absurd Alhazred
Mar 27, 2010

by Athanatos

Twerk from Home posted:

I have to get a C++ project from 2011 to build, and I'm having a hell of a time. I'd like to be able to just get a working binary out with as little fuss as possible, but right at the entry point in global scope it starts with
code:
using namespace boost;
using namespace std;
which causes pretty much any modern compilers and cstd libs to explode. I guess that when this was originally being developed, the version of boost that was included in the includes directory was synchronized to the stdlib version on the development machine?

Long story short, I've got a ton of ambiguous references, and I'm not even sure where to start. Just remove all "using" statements and be specific about namespace where things are called?

It's more that since then a lot of boost stuff emigrated to std. I think shared_ptr, unique_ptr, etc, started in boost. So just be specific; I think it might be easier for you to start by removing "using namespace boost", adding "boost::" to the names that aren't found, then maybe doing the same with "using::std", if you're not one of those freaks who is okay with that.

Twerk from Home
Jan 17, 2009

This avatar brought to you by the 'save our dead gay forums' foundation.

Absurd Alhazred posted:

It's more that since then a lot of boost stuff emigrated to std. I think shared_ptr, unique_ptr, etc, started in boost. So just be specific; I think it might be easier for you to start by removing "using namespace boost", adding "boost::" to the names that aren't found, then maybe doing the same with "using::std", if you're not one of those freaks who is okay with that.

That's where I was starting. It looks like I might just need to update boost as well, because even after starting down that path, I'm still getting ambiguous pair from trying to include just a single boost class: "include/boost/functional/hash/extensions.hpp:34:33: error: reference to 'pair' is ambiguous" looks a hell of a lot like: https://marc.info/?l=boost-bugs&m=132481728414582&w=2 and that issue was fixed about 6 years ago: https://svn.boost.org/trac10/ticket/6323

OK. Updating boost it is!

Absurd Alhazred
Mar 27, 2010

by Athanatos

Twerk from Home posted:

That's where I was starting. It looks like I might just need to update boost as well, because even after starting down that path, I'm still getting ambiguous pair from trying to include just a single boost class: "include/boost/functional/hash/extensions.hpp:34:33: error: reference to 'pair' is ambiguous" looks a hell of a lot like: https://marc.info/?l=boost-bugs&m=132481728414582&w=2 and that issue was fixed about 6 years ago: https://svn.boost.org/trac10/ticket/6323

OK. Updating boost it is!

That's usually a good idea anyway. :unsmith:

The Phlegmatist
Nov 24, 2003

Twerk from Home posted:

code:
using namespace boost;
using namespace std;

lol, you must be working at my job

Anyway you'll need to go through every library call to disambiguate between Boost calls and stdlib calls. The interface for most of them is the same if the Boost libraries were ported to standard so it's not too difficult, just tedious.

Twerk from Home
Jan 17, 2009

This avatar brought to you by the 'save our dead gay forums' foundation.

Absurd Alhazred posted:

That's usually a good idea anyway. :unsmith:

Not if the original boost library included with the code was customized! I guess I'm just hosed, because it was using a custom boost that had subgraph::remove_vertex implemented. I've been looking through old boost versions to figure out what version was originally included, and that function shows up in 1.34, was commented out in 1.45 right here, and was never anything but an assert(false) in between.

Either this is a boost that was pulled from the trunk during one hot minute when that was implemented and then undone before a version release, this is from some branch of boost that never merged to master, or the original developers of this application modified boost. Does this look familiar to anyone? This is the included boost subgraph.hpp, that doesn't match any released version of boost that I can find:
code:
// TODO: Under Construction
template <typename G>
void remove_vertex(typename subgraph<G>::vertex_descriptor u, subgraph<G>& g)
{
	if ( !g.is_root() )
	{
		typename std::map< typename subgraph<G>::vertex_descriptor, typename subgraph<G>::vertex_descriptor>::iterator
	        i = g.m_global_vertex.find(u);
		if ( i != g.m_global_vertex.end() )
		{
			g.m_local_vertex.erase( i->second );
			g.m_global_vertex.erase( i );
		}
	}
	remove_vertex( u , g.m_graph );
}
Another update: I found a built binary from the machine it was developed on. It fails the tests that binary was used to create, 7 years ago. I have no idea what's going on. I wonder if I can just paste in this implementation of remove_vertex.

Here's some discussion about why subgraph::remove vertex is marked wontfix: https://svn.boost.org/trac10/ticket/4752. I guess I don't really have a question anymore, but I wanted to vent about this insanity.

Twerk from Home fucked around with this message at 06:12 on Feb 11, 2018

Absurd Alhazred
Mar 27, 2010

by Athanatos

Twerk from Home posted:

Here's some discussion about why subgraph::remove vertex is marked wontfix: https://svn.boost.org/trac10/ticket/4752. I guess I don't really have a question anymore, but I wanted to vent about this insanity.

Wow, that's really counter-intuitive for me. Their argument is really specific to their implementation of graphs, but all of my encounters with boost libraries have had them try and be as specifics-agnostic as humanly possible.

Dren
Jan 5, 2001

Pillbug
I’m doing stuff with a shared memory segment holding a C++ object or struct. After reading the strict aliasing stuff on the last few pages I’m wondering if there’s anything I wasn’t thinking about that I should be.

On the create side I placement new the type into the memory segment after it’s set up then use it with the resulting pointer (I know the destructor needs to be called manually). On the connect side I static_cast the void * to the object type T *. As I understand it, the connect side behavior breaks the strict aliasing rules. Is this correct? Would that even matter since the contents of the void * can’t even be accessed so the situation where the optimizer might break the code due to accesses from both pointer types should never happen?

nielsm
Jun 1, 2009



Probably make sure any data members are protected with synchronization. I think this is a situation where you should use 'volatile'.

pseudorandom name
May 6, 2007

void* can alias anything and volatile doesn’t do any synchronization

nielsm
Jun 1, 2009



pseudorandom name posted:

void* can alias anything and volatile doesn’t do any synchronization

I didn't mean to use volatile for synchronization, but rather to inhibit optimizations, where the compiler might assume that a value written to a field stays the same later in the flow.

Dren
Jan 5, 2001

Pillbug
I have higher level synchronization with semaphores. The semaphores are used to pass the segment from one program to the other, and logical access to the segment is guarded inside a moveable type so no one *should* access it when they don’t have ownership (though they could save off a pointer if they were determined to mess things up). I don’t think volatile is necessary in this case since when one program wants to use the object inside the segment they have to get the pointer again rather than having kept it around such that the compiler might think it’s old.


pseudorandom name posted:

void* can alias anything and volatile doesn’t do any synchronization

I thought void * being able to alias anything means that
code:
void* p = &something; // ok
auto s = static_cast<Something*> p; // undefined behavior

eth0.n
Jun 1, 2012

Dren posted:

I thought void * being able to alias anything means that
code:
void* p = &something; // ok
auto s = static_cast<Something*> p; // undefined behavior

No error there assuming Something is the real type of something.

e: also assuming Something isn't a function type...

Dren
Jan 5, 2001

Pillbug

eth0.n posted:

No error there assuming Something is the real type of something.

e: also assuming Something isn't a function type...

Yep, it’s the real type and not a function type. Thanks.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
Yeah, strict aliasing is all about accessing objects using the wrong type for the actual object. If you’re placement-new’ing an object into memory and then accessing it as that same type, you’re fine; it doesn’t matter what intermediate types you might have had pointers to if you never actually accessed the memory. void* is not special.

SuperKlaus
Oct 20, 2005


Fun Shoe
Hi I'm a new programmer and an idiot. I swear I'm not asking you to do my homework. My program does everything it is supposed to do except for this hitch here that I'm a bit puzzled about. It's an assignment to make a special class to handle really, really big numbers (Googling around shows me it's a fairly common assignment). My overloaded division isn't working right.

code:
HugeInteger HugeInteger::operator/(const HugeInteger& op2) const{
  int divisions = 0;
  HugeInteger middleman = *this;
  while(middleman >= op2){
    middleman = middleman - op2;
    divisions++;
  }
  HugeInteger temp{divisions};
  return temp;
}
In testing I've found out what it's doing is that the divisions value is looping around after 9 back to 0. Like it reports the following solutions: 99/11 = 9 (correct) but 110/11 = 0 and 242/11 = 2. If I just outright put an integer like I dunno 12 in as HugeInteger temp's parameter it converts and reports that correctly. Thus something's wrong with my divisions++ or the loop or something.

I'm a few semesters in and this seems like a total intro to programming problem and I should know better. What's my error?

Dren
Jan 5, 2001

Pillbug
The algorithm seems right. Within your function you invoke HugeInteger’s copy constructor, operator>=, operator=, operator-, and construction from an initializer list. Perhaps there is an error in one of them. Test each one individually.

There are many practices you can adopt if you want to be sure of the correctness of your program. Expects and Ensures check preconditions and postconditions of methods (you can just use asserts if you don’t feel like pulling in the gsl). Unit test frameworks provide niceties to help hammer your methods with edge cases and find exactly where they fail. Lastly, you could learn to use the debugger instead of debugging with print statements. All of these things involve extra up front effort but if you employ them to check your assumptions they will prevent a great many head scratcher bugs like this one.

Harik
Sep 9, 2001

From the hard streets of Moscow
First dog to touch the stars


Plaster Town Cop
Curious as to what's going on here:

C++ code:
#include <functional>
#include <memory>

struct foo {
    int v;
    foo(int v) : v(v) {}
};

void run(std::function<void()> r) {
    r();
}

int main(int, char **) {
    auto main_ptr = std::make_unique<foo>(1);
    run( [ lambda_ptr = std::move(main_ptr) ] () {
        printf("lambda: %d\n", lambda_ptr->v);
    });

    return 0;
}
This should work in C++14, but it explodes when I try to do it. It makes sense, since you can't copy around a unique pointer and std::function is copyable. So, given this is explicitly supposed to be possible per the C++14 FAQ, how should it be done?

Absurd Alhazred
Mar 27, 2010

by Athanatos

Harik posted:

Curious as to what's going on here:

C++ code:
#include <functional>
#include <memory>

struct foo {
    int v;
    foo(int v) : v(v) {}
};

void run(std::function<void()> r) {
    r();
}

int main(int, char **) {
    auto main_ptr = std::make_unique<foo>(1);
    run( [ lambda_ptr = std::move(main_ptr) ] () {
        printf("lambda: %d\n", lambda_ptr->v);
    });

    return 0;
}
This should work in C++14, but it explodes when I try to do it. It makes sense, since you can't copy around a unique pointer and std::function is copyable. So, given this is explicitly supposed to be possible per the C++14 FAQ, how should it be done?

Why not just pass it by reference? It's only used within the lifetime of your main, anyway.

SuperKlaus
Oct 20, 2005


Fun Shoe

Dren posted:

The algorithm seems right. Within your function you invoke HugeInteger’s copy constructor, operator>=, operator=, operator-, and construction from an initializer list. Perhaps there is an error in one of them. Test each one individually.

There are many practices you can adopt if you want to be sure of the correctness of your program. Expects and Ensures check preconditions and postconditions of methods (you can just use asserts if you don’t feel like pulling in the gsl). Unit test frameworks provide niceties to help hammer your methods with edge cases and find exactly where they fail. Lastly, you could learn to use the debugger instead of debugging with print statements. All of these things involve extra up front effort but if you employ them to check your assumptions they will prevent a great many head scratcher bugs like this one.

You are wise. My operator>= was screwy.

Harik
Sep 9, 2001

From the hard streets of Moscow
First dog to touch the stars


Plaster Town Cop

Absurd Alhazred posted:

Why not just pass it by reference? It's only used within the lifetime of your main, anyway.

Because this is clearly a toy example and the actual usecase is avoiding doing disk IO loading the .wav file in the audio thread? Normally, all the audio is loaded at startup, but I had to add new samples at runtime, so I made the "obvious" change to do the work on the calling thread:

C++ code:
void LoadSample_old(std::string name) {
    audio_workqueue.send([name]{
        sample_map[name] = Sample::Load(name);
    });
}

void LoadSample(std::string name) {
    std::unique_ptr<Sample> s = Sample::Load(name);
    audio_workqueue.send([name, s = std::move(s)]{
        sample_map[name] = s;
    });
}
When it didn't work I just did explicit allocation and then encapsulated the pointer inside the lambda, but I was surprised that it didn't work when it was supposed to according to the c++14 info and Snackoverflow.

G++7 and clang-5.

E: I can't put a mutex around sample_map because that puts the lock in the hotpath of feeding audio. By just doing the assignment the workqueue can be run as soon as the audio buffers are filled.

code:
  wait_buffer_ready();
  mix_audio();
  fill_buffer();
  run_workqueue();
mix_audio is fast enough to not get let the buffers underflow - but it can't have any locks. If I move it before the wait() it adds extra audio latency. The only locks are in run_workqueue() which happens only after the audio buffers are completely topped off. If I run something heavy in there, though, like touching the disk? *pop*.

Harik fucked around with this message at 02:12 on Feb 12, 2018

Absurd Alhazred
Mar 27, 2010

by Athanatos

Harik posted:

Because this is clearly a toy example and the actual usecase is avoiding doing disk IO loading the .wav file in the audio thread? Normally, all the audio is loaded at startup, but I had to add new samples at runtime, so I made the "obvious" change to do the work on the calling thread:

C++ code:
void LoadSample_old(std::string name) {
    audio_workqueue.send([name]{
        sample_map[name] = Sample::Load(name);
    });
}

void LoadSample(std::string name) {
    std::unique_ptr<Sample> s = Sample::Load(name);
    audio_workqueue.send([name, s = std::move(s)]{
        sample_map[name] = s;
    });
}
When it didn't work I just did explicit allocation and then encapsulated the pointer inside the lambda, but I was surprised that it didn't work when it was supposed to according to the c++14 info and Snackoverflow.

G++7 and clang-5.

Are you sure your problem isn't that you're naming what you're moving to the same as what you're moving from? What happens if you use this:

C++ code:
void LoadSample(std::string name) {
    std::unique_ptr<Sample> s = Sample::Load(name);
    audio_workqueue.send([name, s2 = std::move(s)]() mutable {
        sample_map[name] = s2;
    });
}
Then I notice that when you're assigning to sample_map, you're not using move. What happens when you try this?
C++ code:
void LoadSample(std::string name) {
    std::unique_ptr<Sample> s = Sample::Load(name);
    audio_workqueue.send([name, s2 = std::move(s)]() mutable {
        sample_map[name] = std::move(s2);
    });
}

Lime
Jul 20, 2004

Harik posted:

This should work in C++14, but it explodes when I try to do it. It makes sense, since you can't copy around a unique pointer and std::function is copyable. So, given this is explicitly supposed to be possible per the C++14 FAQ, how should it be done?

unique_ptr is move-only so a lambda that captures it is also move-only, and std::function can only hold copyable callables. The rationale for that is that the very type erasure you're using std::function for also means it can't just disable copy constructors/operators at compile time if it's constructed from a move-only type. That type information only exists within the constructor. It could set some flag during construction that would make it throw an exception if you tried to copy a std::function after filling it with a move-only type, but that's a design choice and the language committee decided against it. I guess it's just nicer to know you can always copy a std::function.

The FAQ you linked is talking about a situation more like:

C++ code:
struct foo {
    int v;
    foo(int v) : v(v) {}
};

template <typename F>
void run(F f) {
    f();
}

int main(int, char **) {
    auto main_ptr = std::make_unique<foo>(1);
    run( [ lambda_ptr = std::move(main_ptr) ] () {
        printf("lambda: %d\n", lambda_ptr->v);
    });

    return 0;
}
which works fine.

EDIT: As for the details you gave about your real use-case: you're just going to have give up on capturing a unique_ptr. The generally accepted next-best-solution is to just use shared_ptr.

Lime fucked around with this message at 02:29 on Feb 12, 2018

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

Harik posted:

This should work in C++14, but it explodes when I try to do it. It makes sense, since you can't copy around a unique pointer and std::function is copyable. So, given this is explicitly supposed to be possible per the C++14 FAQ, how should it be done?

Downgrade the unique pointer to a shared pointer; or, if you absolutely need a unique pointer, store a shared pointer to a unique pointer

It's the unfortunate reality of std::function, don't fight it. Yes, other frameworks have universal function pointers that do support move-only functors, but not the standard library

e: Hell, I think I may have worked around it by writing an utility routine that makes move-only functors copyable by moving them to the heap, making a shared pointer to the moved functor, capturing the shared pointer in a lambda that forwards calls to the moved functor, and returning the lambda. Pretty gross but at least it keeps the rest of the code clean

hackbunny fucked around with this message at 02:32 on Feb 12, 2018

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS

SuperKlaus posted:


code:
HugeInteger HugeInteger::operator/(const HugeInteger& op2) const{
  int divisions = 0;
  HugeInteger middleman = *this;
  while(middleman >= op2){
    middleman = middleman - op2;
    divisions++;
  }
  HugeInteger temp{divisions};
  return temp;
}

Fwiw I think you have another error besides the one stated. Hint below if you want it.

It's another case where you are going to return too small a value.

Adbot
ADBOT LOVES YOU

Harik
Sep 9, 2001

From the hard streets of Moscow
First dog to touch the stars


Plaster Town Cop
Thanks, everyone. I thought it was a problem with run(), but the limits of capturing unique_ptr make more sense now. Funny, given that I use unique_ptr and cross-thread runqueues everywhere but I've managed to never run into this until now.

There's a landmine with my edited solution (allocate with new outside, pass the raw pointer, put into a unique_ptr inside the lambda.) If something changes and the lambda gets called twice it will wrap the "unique" pointer twice, and since the name is the same it will destroy the Sample right before it assigns the map the pointer to now-dead memory. I don't know why I'd change the workqueue to possibly run more than once, but it's still a landmine. Worst case before was eating the disk IO twice, which would be cached the second time anyway.

Ended up making a second queue of (name, unique_ptr<Sample>) and importing everything from that where I have the runqueue(). The locking is trivial and I shouldn't ever be doing more than one sample update per frame, so my worst case cost is something like:

code:
work thread            audio thread
s = LoadSample(name)
queue_lk.lock()        *block on lock*
queue.append(name, s)
queue_lk.unlock()      *unblock*
                       queue_lk.lock()
                       pair p = queue.pop()
                       map[p.name] = p.sample
                             (replace?  deconstruct old sample)
                       queue_lk.unlock()

Which should never be enough latency to cause a pop - there's still no IO on the hot path. More code but the inter-dependencies are much clearer.

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