|
Slurps Mad Rips posted:Bit of a waste, since shared_ptr allocates a control block. Now you've got two ref counts, *and* you're wasting a lot of extra space for just one pointer. 🤷♀️ Oh yeah, for sure. I only suggest it because it's dead simple and OP said they'd prefer using a standard library type.
|
# ? Jul 20, 2019 15:40 |
|
|
# ? May 10, 2024 13:11 |
|
DIY is probably less code than trying to use any existing helper. Binding to external refcounting is really simple, if slightly error-prone.
|
# ? Jul 20, 2019 22:02 |
|
Yeah I ended up rolling my own because it's something I'm working on for fun, and rolling my own was fun, and also because I didn't want to deal with adding boost. Gonna take a look at that proposal one though. edit: also because the boost version relies on free functions to handle increment/decrement and I can just call the one method I need. big black turnout fucked around with this message at 06:28 on Jul 21, 2019 |
# ? Jul 21, 2019 06:23 |
|
Slurps Mad Rips posted:I might suggest looking into my proposed (and currently on track for C++23) retain_ptr instead, since you don't have to worry about the "retain by default" semantic and having to pass "false" everywhere you want to adopt a pointer Yeah, I like this a lot better than the boost version, I think. I chose to go the opposite direction of yours and call my method release instead of detach. I also lol'd at quote:Comedy Option:
|
# ? Jul 21, 2019 06:45 |
|
retain_ptr does look really nice, actually!
|
# ? Jul 21, 2019 19:19 |
|
I'm trying to figure out a linking error I'm stuck with at work. For the record, I do not have a firm grasp on C++ in general. I'm working on an (ancient) application that refers to a third party DLL for several important functions. This DLL is used through explicit linking, and I've recently replaced it with a newer version of the DLL that had renamed most of the functions. So far so good. However, to work with the new version, we need to convert our source files to the format the new version of the DLL expects. We've been provided another DLL file which provides a function for this, and I tried to set that up similar to the existing implementations. We are not given .lib files, so implicit linking is out. The header file for the conversion DLL was not provided, but I was given enough information about the single function it contained that I was able to create one. I've also added relevant calls to LoadLibrary and GetProcAddress, and implemented a call to the conversion function at the appropriate time. At this point the application compiles without errors, but I then get linking errors (LNK2019 and LNK2028, both referring to the same function call). Based on my (limited) understanding of explicit linking, this should not be happening - even if the function header is completely different from the actual function in the DLL, since nothing actually checks whether the function exits until runtime. I've been trying to find differences with the other DLL and header file we were provided, but I'm coming up short. Apparently the conversion dll isn't using _stdcall (the other dll does for all functions) - but again, this is something that to my understanding would not be relevant until runtime. Google isn't helpful, since it apparently decided that "implicit" and "explicit" are interchangeable words. Any known common culprits for this?
|
# ? Jul 23, 2019 19:21 |
|
Nostalgamus posted:I'm trying to figure out a linking error I'm stuck with at work. For the record, I do not have a firm grasp on C++ in general. If you're explicitly loading the library, then you shouldn't be statically linking to it at all. Either create your own functions with the same signatures that will be essentially callbacks working through the function pointers provided from the DLL, or just create a wrapper for the new functionality, or both, depending on what'll make things easier for you.
|
# ? Jul 24, 2019 02:15 |
|
Yes, it's been a month because I accidentally took this thread off my control panel, but:qsvui posted:What type information? code:
Anyway, C++/unit testing question: You nearly always want to only test the public interface of a class, so close to always it's basically universal. Except an edge case: handle allocation rollover, timer rollover - things that a class keeps as state but requires a long runtime to possibly expose bugs on. As an example, a resource manager returns opaque handles that must be unique over a reasonable time period. A pointer to the memory isn't unique in that sense because you can release a resource and immediately request one and get the exact same pointer. A serial number works, but eventually rolls over, so a long-lived resource at ID 0 will be duplicated eventually. How do you unit test without looping to MAXINT? Something like this is clearly a self-contained piece of functionalty that screams to be made into a generic class, but you still have to expose the internal serial number state to advance it in a test, and that makes the details of the implementation part of the API. I'm thinking protected visibility instead of private, and extend it into a TestableFoo class which just adds getters/setters. Has anyone solved it in a different, probably better way?
|
# ? Jul 24, 2019 03:34 |
|
One thought that comes to mind is to move that functionality into a generic class like you suggested and then to require a reference to that class in your resource manager's constructor. If you don't want to specify a concrete type for that reference, you could use an abstract interface or a template parameter. Then in your tests, you use fake versions of the serial number class.
|
# ? Jul 25, 2019 04:13 |
|
Harik posted:I'm thinking protected visibility instead of private, and extend it into a TestableFoo class which just adds getters/setters. Has anyone solved it in a different, probably better way?
|
# ? Jul 25, 2019 04:27 |
|
#define private public #define protected public #define class struct
|
# ? Jul 25, 2019 05:14 |
|
qsvui posted:One thought that comes to mind is to move that functionality into a generic class like you suggested and then to require a reference to that class in your resource manager's constructor. If you don't want to specify a concrete type for that reference, you could use an abstract interface or a template parameter. Then in your tests, you use fake versions of the serial number class. That smells right, and the rest of the resource-creation is heavy enough that that an extra dereference would not remotely be an issue. Thanks!
|
# ? Jul 25, 2019 13:36 |
|
Another technique is to use a pimpl and structure your library code like this:code:
|
# ? Jul 26, 2019 02:57 |
|
Honestly, I've switched to just making "private but accessible to tests" members public with a python style underscore postfix. It's just not a fight worth fighting. It's obvious, trivial to catch in a code review, and prevents me from comprimising designs just for the sake of testability. Maybe one day I'll write a clang-tidy tool to check for that, but I seriously doubt that'll actually improve anything.
Aramis fucked around with this message at 21:32 on Jul 29, 2019 |
# ? Jul 29, 2019 21:18 |
|
Aramis posted:Honestly, I've switched to just making "private but accessible to tests" members public with a python style underscore postfix. It's just not a fight worth fighting. It's obvious, trivial to catch in a code review, and prevents me from comprimising designs just for the sake of testability. Maybe one day I'll write a clang-tidy tool to check for that, but I seriously doubt that'll actually improve anything. But like this: real header file code:
code:
|
# ? Jul 30, 2019 00:34 |
|
Couldn’t you write a static analysis that methods ending in __ are only called from within the class or within files starting with `test-`?
|
# ? Jul 30, 2019 00:40 |
|
Why not work with C++ and Intellisense or whatever the equivalent is in other IDE's? Why create another layer you need to conform with that won't pop up as easily?
|
# ? Jul 30, 2019 01:03 |
|
Y’all are solving the wrong problem; you shouldn’t be testing the internal implementation details of your classes like that, it creates very brittle tests. If you can’t test your class using only its public methods, it’s doing too much and needs to be broken into pieces that can be tested individually.
|
# ? Jul 30, 2019 02:02 |
|
Aramis posted:Honestly, I've switched to just making "private but accessible to tests" members public with a python style underscore postfix. It's just not a fight worth fighting. It's obvious, trivial to catch in a code review, and prevents me from comprimising designs just for the sake of testability. Maybe one day I'll write a clang-tidy tool to check for that, but I seriously doubt that'll actually improve anything. But in python there’s name mangling on __ prefixed stuff to prevent an accident. __ prefix is both trivial to catch in a code review and trivial to miss in a code review. And it’s very tempting for someone who is new or under time pressure to use the public as a public. The friend method seems preferable to this solution. Adding #ifdef TESTING around the friend declaration and building the test with -DTESTING would further clarify the intent and ensure that the friend declaration never shows up in production. Adhemar posted:Y’all are solving the wrong problem; you shouldn’t be testing the internal implementation details of your classes like that, it creates very brittle tests. If you can’t test your class using only its public methods, it’s doing too much and needs to be broken into pieces that can be tested individually. Nah. Sometimes a class has a private thing that isn’t part of the public interface but is nonetheless important to test on its own. And nothing else uses that thing so breaking it out is overkill. Related: have you guys heard about fseam for mocking?
|
# ? Jul 30, 2019 11:28 |
|
Dren posted:Nah. Sometimes a class has a private thing that isn’t part of the public interface but is nonetheless important to test on its own. And nothing else uses that thing so breaking it out is overkill. Edit: oh, also if you asked it for data newer than the latest streamed data the request would block until newer data comes in, or a timeout. Testing all that in one giant mess test is no bueno.
|
# ? Jul 30, 2019 14:55 |
|
Dren posted:Nah. Sometimes a class has a private thing that isn’t part of the public interface but is nonetheless important to test on its own. And nothing else uses that thing so breaking it out is overkill. That’s not the only criterion for breaking something out. If a class is this complex, the inability to properly test it is a symptom of that, not the problem. Breaking the class up can help. You may even find a use for the newly extracted piece later, but that’s not required.
|
# ? Jul 30, 2019 16:19 |
|
Adhemar posted:That’s not the only criterion for breaking something out. If a class is this complex, the inability to properly test it is a symptom of that, not the problem. Breaking the class up can help. You may even find a use for the newly extracted piece later, but that’s not required. I like this better if it falls in with my physical layout suggestion from earlier for a library: code:
Harik posted:As an example, a resource manager returns opaque handles that must be unique over a reasonable time period. A pointer to the memory isn't unique in that sense because you can release a resource and immediately request one and get the exact same pointer. A serial number works, but eventually rolls over, so a long-lived resource at ID 0 will be duplicated eventually. stuff in include/ - the public interface ResHandle.h - opaque handle to resource code:
ResHandle.cpp code:
code:
code:
The tests are allowed to include from src/ so they can see the private implementations that aren't normally exposed publicly. test.cpp code:
Dren fucked around with this message at 16:54 on Jul 30, 2019 |
# ? Jul 30, 2019 16:52 |
|
If you're tempted to use friends, you might as well just cut out the middleman and make the data public or create a public accessor. You can also give this accessor a name that stands out as being for testing only so that it can be caught at code reviews. I'd argue that breaking up functionality and using dependency injection does more than just enable testing and so it should be preferred. But if you can't be bothered then I don't see the point in being cute. If someone abuses a public function that's labelled test only, would they really be discouraged from using a test only friend?
|
# ? Jul 31, 2019 04:14 |
|
Why the heck would I use a special name and require people to catch misuse in code reviews, when I could accomplish the exact same thing in a way where the compiler will prevent any misuse?
|
# ? Jul 31, 2019 05:10 |
|
qsvui posted:If you're tempted to use friends, you might as well just cut out the middleman and make the data public or create a public accessor. You can also give this accessor a name that stands out as being for testing only so that it can be caught at code reviews. Public accessor functions would be functions that you're putting into your real non-test code and hoping the compiler/linker will strip out as unused in non-test builds. A friend declaration always compiles to literally nothing, and the associated functions (if any) are in a test file that's not part of a non-test build. I think you're trying to say dependency injection is better, and sure, in many circumstances it is. But saying "so if you don't use dependency injection you might as well just take a huge poo poo on your code for no reason" is ridiculous. roomforthetuna fucked around with this message at 05:50 on Jul 31, 2019 |
# ? Jul 31, 2019 05:46 |
|
Admittedly, I didn't consider compiling the friend classes separately. But even so, what's to prevent someone just creating their own class of the same friend name and using it in a non-test build? If someone is already ignoring a clear convention, then one extra hoop to jump through won't stop them. I've heard it argued that your tests are also a client of your code. If the client can't use your code, then the code is not fulfilling all of its requirements. Making things public is one way to meet them.
|
# ? Jul 31, 2019 06:02 |
|
Yes, forcing someone to jump through hoops in order to do the wrong thing is way better than making it trivially easy to do the wrong thing. I'm not sure how that's even a point of discussion.
|
# ? Jul 31, 2019 06:09 |
|
qsvui posted:Admittedly, I didn't consider compiling the friend classes separately. But even so, what's to prevent someone just creating their own class of the same friend name and using it in a non-test build? If someone is already ignoring a clear convention, then one extra hoop to jump through won't stop them. It depends on the thing. Sometimes injection makes it clearer and testing easier, like if you inject the same thing in multiple places and/or have a well defined fake or mock for it then dependency injection can be great. But if you find yourself doing dependency injection as a one-off specifically for testing one class that you could test directly if you had access to a few private variables, just use a friend test, it's a good clean solution.
|
# ? Jul 31, 2019 06:28 |
|
You can't really stop actively malicious users from modifying your objects anyway, since they can just reinterpret cast them. Exposing the member variables means that they will be shown as autocomplete suggestions for all usages of the class.
|
# ? Jul 31, 2019 06:59 |
|
roomforthetuna posted:It's not about stopping someone from doing the wrong thing on purpose, it's about stopping someone from doing the wrong thing by mistake because they're not familiar with some weird convention someone just made up, like the original proposal of an underscore prefix meaning "treat this as private unless you're a test even though it's literally public". It's also about not compiling poo poo into your real code that isn't actually being used. Dependency injection suffers from that - if it's something you're only doing in aid of tests, is it really worth having an actual performance penalty and additional complexity in your real code so that you can test something, when you could have done it another way, that isn't any harder, without that performance penalty or complexity? The convention doesn't have to be that weird. If you have a function called GetTestOnlyStuff() or some other obnoxious name, then you'd have to be willfully ignorant in claiming that you didn't know that you weren't supposed to use it in production code. Also, you can still compile the test only stuff separately. For example: C++ code:
C++ code:
C++ code:
|
# ? Jul 31, 2019 07:33 |
|
Compilers get a lot of poo poo for not being sufficiently smart but they are sufficiently smarter than code reviewers.
|
# ? Jul 31, 2019 07:39 |
|
You seem to vastly overestimate the amount of 'boilerplate' involved in making something a friend class (serious request here: can you put a number on how much you think it costs?), and vastly underestimate the costs of your proposed bespoke conventions. Why are you so opposed to having the compiler enforce visibility?
|
# ? Jul 31, 2019 07:45 |
|
Jabor posted:You seem to vastly overestimate the amount of 'boilerplate' involved in making something a friend class (serious request here: can you put a number on how much you think it costs?), and vastly underestimate the costs of your proposed bespoke conventions. I don't mean to give that impression, I was just trying to convey what I considered to be a pragmatic option even though it may not be considered "proper OO design". And by cost, I don't know if you mean computing resources, but test code is still code you have to maintain. I don't know how common this friend class usage is, but writing several of these have to be tedious. Maybe you can come up with a generic solution but I'm sure there will have to be special cases for which you have to come up with bespoke code.
|
# ? Jul 31, 2019 09:03 |
|
You can literally just write friend class MyClassTest;
|
# ? Jul 31, 2019 09:15 |
qsvui posted:I don't mean to give that impression, I was just trying to convey what I considered to be a pragmatic option even though it may not be considered "proper OO design". And by cost, I don't know if you mean computing resources, but test code is still code you have to maintain. I don't know how common this friend class usage is, but writing several of these have to be tedious. Maybe you can come up with a generic solution but I'm sure there will have to be special cases for which you have to come up with bespoke code. C++ code:
|
|
# ? Jul 31, 2019 09:26 |
|
Hmm, I was using the earlier given Testicle class as a reference. I've never used a test framework that required you to create classes that derive from a test hook base class (I assume that's what's going on).
|
# ? Jul 31, 2019 09:48 |
The test class deriving from a base doesn't matter for the friend declaration to work, as long as the test code is in a named class that named class can be declared friend.
|
|
# ? Jul 31, 2019 10:08 |
|
An alternative option would be to write a TESTONLY macro that evaluates to public in a test, but private otherwise, and then writing something like:code:
Though you have to be a bit careful there, because then your unit tests will still pass if someone inadvertantly uses the test-only api in the real code.
|
# ? Jul 31, 2019 10:09 |
|
nielsm posted:The test class deriving from a base doesn't matter for the friend declaration to work, as long as the test code is in a named class that named class can be declared friend. Yeah, I meant that I never used a framework where you have to override something like a RunTest method. That looks neater for this case, but if you're using a framework like the one in that Testicle example earlier, then your class has to have that constructor and you have to define accessors for each thing that you're interested in that does nothing more than return the value, etc.
|
# ? Jul 31, 2019 10:30 |
|
|
# ? May 10, 2024 13:11 |
|
qsvui posted:Yeah, I meant that I never used a framework where you have to override something like a RunTest method. That looks neater for this case, but if you're using a framework like the one in that Testicle example earlier, then your class has to have that constructor and you have to define accessors for each thing that you're interested in that does nothing more than return the value, etc. You've already needed three of those lines for the test framework with the override, but somehow that's more convincing to you. I guess that has the advantage that you *don't* need any kind of accessor functions any more. Joke option that's less boilerplate, at the top of your test file #define private public and #define protected public, now it's only two lines of boilerplate and you can access all the things you want from tests! roomforthetuna fucked around with this message at 16:11 on Jul 31, 2019 |
# ? Jul 31, 2019 16:09 |