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
Slurps Mad Rips
Jan 25, 2009

Bwaltow!

netcat posted:

Here's something I thought was kinda strange. The following does not compile:

code:
#include <vector>
#include <iostream>
 
struct foo
{
 int x;
 char name[8];
};
 
 static std::vector<foo> b = {
    { 1, "a" },
    { 2, "b" }
 };
 
int main()
{
    for (auto it = b.begin(); it != b.end(); ++it)
    {
        std::cout << it->name << "\n";
    }
    
    return 0;
}
prog.cpp:13:2: error: could not convert ‘{{1, "a"}, {2, "b"}}’ from ‘<brace-enclosed initializer list>’ to ‘std::vector<foo>’

http://ideone.com/UlCXDN

But if I instead use { 'a', '\0' } when creating the char-arrays, it compiles just fine. Why does it work like that?

This is a bug with GCC, though all is not as it appears. If we change the std::vector<foo> to a std::array<foo, 2>, it will compile (We add the extra braces for aggregate initialization that std::array requires of course). However, removing the = sign shows a different set of compiler errors:

code:
error: no matching function for call to 'std::vector<foo>::vector(<brace-enclosed initializer list>)'
And then it begins to dump some SFINAE to us (i.e., "These are the constructors I can choose from, but you gave me this!"). Looking closely at the output, we'll see that it doesn't ever refer to the list of brace enclosed initializers as anything but (When in an ideal world it would say it was a std::initializer_list<foo> because that's what we want to create). Basically, gcc is trying to infer the constructor it needs to call at a very shallow level, and doesn't try to treat these initializers as foos, but just raw dumb unnamed brace enclosed initializers. If we are a little more explicit for GCC, it will take our arguments for the proper constructor:

code:
static std::vector<foo> b {
   foo { 1, "a" },
   foo { 2, "b" },
};
Which results in a std::initializer_list<foo> being built.

This is definitely a bug, just not the bug it seems to be. I've run into this with a recursive variadic unrestricted union-like variant class I was writing for a while. Huge PITA, and it basically destroys the point of having a variant in the first place. Bit of a show stopper. :(

Adbot
ADBOT LOVES YOU

bobua
Mar 23, 2003
I'd trade it all for just a little more.

Is there any benefit to declaring a couple of these variables outside of this loop? For example, if I declared 'glyph' before the loop, and then set it to Mat::zeros... within the loop, would that keep using the same bit of memory vs using a new bit of memory each time through the loop?

code:
std::vector<Mat>* FixGlyphs(Mat* sourceImage, std::vector<std::pair< std::vector<cv::Point>, std::vector<cv::Point>>>* glyphs)
{
	std::vector<Mat> glyphImages;
	for( std::pair< std::vector<cv::Point>, std::vector<cv::Point>> g : *glyphs)
	{	
		Mat glyph = Mat::zeros(110,110, CV_8UC3);
		std::vector<cv::Point> glyphCorners;
		glyphCorners.push_back(cv::Point2f(0,0));
		glyphCorners.push_back(cv::Point2f(glyph.cols,0));
		glyphCorners.push_back(cv::Point2f(glyph.cols,glyph.rows));
		glyphCorners.push_back(cv::Point2f(0,glyph.rows));
		Mat perspectiveMatrix  = cv::getPerspectiveTransform(g.second, glyphCorners);
		cv::warpPerspective(*sourceImage, glyph,perspectiveMatrix, glyph.size());
		transpose(glyph, glyph);
		glyphImages.push_back(glyph);
	}
	return &glyphImages;
}

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
If Mat is backed by a heap allocation, then yes, it is likely to perform better if you re-initialize the same allocation every iteration instead of allocating and freeing it each time.

You might also consider not spuriously copying the vectors of points in g and reusing the same vector (or even a fixed-size array) for glyphCorners.

bobua
Mar 23, 2003
I'd trade it all for just a little more.

rjmccall posted:

If Mat is backed by a heap allocation, then yes, it is likely to perform better if you re-initialize the same allocation every iteration instead of allocating and freeing it each time.

You might also consider not spuriously copying the vectors of points in g and reusing the same vector (or even a fixed-size array) for glyphCorners.

Actually, I don't think that code will even work, since glyphCorners wouldn't be cleared out at the start of the next loop, right? I need to have only 4 corners for the perspective matrix function to work.

Vinterstum
Jul 30, 2003

bobua posted:

Actually, I don't think that code will even work, since glyphCorners wouldn't be cleared out at the start of the next loop, right? I need to have only 4 corners for the perspective matrix function to work.

Just do a glyphCorners.clear(). In all practical implementations that doesn't actually deallocate any memory, so repeating that plus the four .push_backs per iteration is cheap.

bobua
Mar 23, 2003
I'd trade it all for just a little more.

Updated to this.

code:
std::vector<Mat>* FixGlyphs(Mat* sourceImage, std::vector<std::pair< std::vector<cv::Point>, std::vector<cv::Point>>>* glyphs)
{
	std::vector<Mat> glyphImages;
	Mat glyph;
	std::vector<cv::Point> glyphCorners;
	Mat perspectiveMatrix;
	for( std::pair< std::vector<cv::Point>, std::vector<cv::Point>> g : *glyphs)
	{	
		glyph = Mat::zeros(110,110, CV_8UC3);
		glyphCorners.clear();
		glyphCorners.push_back(cv::Point2f(0,0));
		glyphCorners.push_back(cv::Point2f(glyph.cols,0));
		glyphCorners.push_back(cv::Point2f(glyph.cols,glyph.rows));
		glyphCorners.push_back(cv::Point2f(0,glyph.rows));
		perspectiveMatrix  = cv::getPerspectiveTransform(g.second, glyphCorners);
		cv::warpPerspective(*sourceImage, glyph,perspectiveMatrix, glyph.size());
		transpose(glyph, glyph);							
		glyphImages.push_back(glyph);
	}
	return &glyphImages;			
}

Vinterstum
Jul 30, 2003

bobua posted:

Updated to this.


Most likely your Mat class doesn't do any heap allocations, in which case moving them outside of the loop likely doesn't make a difference (should be quick to check).

More importantly though, you never want to return the pointer to a stack variable from a function; as soon as the function exits, the stack frame becomes invalid and any stack allocated objects get destructed.

Either return the std::vector by value (probably ok due to return-value optimization), or pass a reference to an output vector as an argument.

Vinterstum fucked around with this message at 23:57 on May 28, 2013

bobua
Mar 23, 2003
I'd trade it all for just a little more.

Vinterstum posted:

Most likely your Mat class doesn't do any heap allocations, in which case moving them outside of the loop likely doesn't make a difference (should be quick to check).

More importantly though, you never want to return the pointer to a stack variable from a function; as soon as the function exits, the stack frame becomes invalid and any stack allocated objects get destructed.

Either return the std::vector by value (probably ok due to return-value optimization), or pass a reference to an output vector as an argument.

How would I check if something does heap allocations just out of curiosity?

Not sure if I understand that last part... Are you saying add something like std::vector<Mat>* myVariable to 'fixGlyphs' argument list, then setting myVariable = &glyphImages instead of using return?

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
I think Mat is heap-backed; among other things, it doesn't seem to have fixed dimensions.

bobua posted:

code:

glyph = Mat::zeros(110,110, CV_8UC3);

I'm guessing that Mat::zeros returns a Mat, right? So this still does a heap-allocation and then copies from that into glyph. If you're going to try to optimize allocations, you really want an in-place version of this.

Vinterstum
Jul 30, 2003

bobua posted:

How would I check if something does heap allocations just out of curiosity?

You'd have to check the actual code of the Mat class. I wouldn't worry too much about it though; your current implementation is fine.

bobua posted:

Not sure if I understand that last part... Are you saying add something like std::vector<Mat>* myVariable to 'fixGlyphs' argument list, then setting myVariable = &glyphImages instead of using return?

No that would still just return a pointer to an object which isn't valid anymore.

Consider a bit more of a minimal example:

code:

std::vector<int>* GetNumberList()
{
  std::vector<int> numbers;
  numbers.push_back(1);
  return &numbers;
}

void ShowSomeNumbers()
{
  std::vector<int>* returnedNumbers = GetNumberList();
  printf("Our number: %u\n", returnedNumbers[0]);
}
The "numbers" variable in GetNumberList() is constructed on the stack when the function gets called, and then it gets destructed when the GetNumberList() function returns. In other words, anything allocated on the stack inside GetNumberList() is only valid within that function; as soon as you return, you can no longer access those variables and expect correct behavior. In the above example, that means that the printf() is accessing something invalid and will potentially crash or return garbage.

The alternatives are:

* Instead of allocating "numbers" on the stack, we could allocate it on the heap. I.e.
code:

std::vector<int>* GetNumberList()
{
  std::vector<int>* numbers = new std::vector<int>;
  numbers.push_back(1);
  return numbers;
}

void ShowSomeNumbers()
{
  std::vector<int>* returnedNumbers = GetNumberList();
  printf("Our number: %u\n", returnedNumbers[0]);
  delete returnedNumbers;
}
Notice that the calling function is now responsible for destroying the returned object, so this is both inefficient and error-prone. It will give the correct behavior though.

* Simpler would just be to return the vector by value rather than returning a pointer to it. In theory this can incur some copying of the vector which would be efficient, but in practice the compiler should optimize this away.

code:

std::vector<int> GetNumberList()
{
  std::vector<int> numbers;
  numbers.push_back(1);
  return numbers;
}

void ShowSomeNumbers()
{
  std::vector<int> returnedNumbers = GetNumberList();
  printf("Our number: %u\n", returnedNumbers[0]);
}
EDIT: Error-prone, not error-proof...

Vinterstum fucked around with this message at 00:30 on May 29, 2013

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

bobua posted:

How would I check if something does heap allocations just out of curiosity?

The easiest way is to think about the type's API. A type's direct storage is always constant-sized, so if Mat can store arbitrary sizes of things, then it has to be heap-backed at some point.

Another way is to look at the fields in the type to see how it stores the elements. If it contains an array (or a std::array), it might not be heap-backed. If it just has a pointer or a std::vector or something like that, it's heap-backed.

A third way is to just look at the implementations of things like the copy-constructor and check for uses of malloc or new.

quote:

Not sure if I understand that last part... Are you saying add something like std::vector<Mat>* myVariable to 'fixGlyphs' argument list, then setting myVariable = &glyphImages instead of using return?

No. Make the function return a std::vector<Mat> directly (not a pointer to one), or add a std::vector<Mat>& argument and just push things onto that directly.

Vinterstum
Jul 30, 2003

rjmccall posted:

I think Mat is heap-backed; among other things, it doesn't seem to have fixed dimensions.

Yeah looks like you're right; this appears to be part of the OpenCV library and in this case used as actual bitmap data for a glyph..? I'm too used to Matrix == Matrix4x4, I guess.

bobua
Mar 23, 2003
I'd trade it all for just a little more.

Okay, I did this before you guys posted, and I'm not getting why it wouldn't work...
code:
int FixGlyphs(Mat* sourceImage, std::vector<std::pair< std::vector<cv::Point>, std::vector<cv::Point>>>* glyphs, std::vector<Mat>* gImages)
{
	std::vector<Mat> glyphImages;
	...
	for( std::pair< std::vector<cv::Point>, std::vector<cv::Point>> g : *glyphs)
	{	
		...								
		glyphImages.push_back(glyph);
	}
	*gImages = glyphImages;							
	return 1;						
}
code:
std::vector<Mat>* MyMat;
FixGlyphs(...,..., MyMat);
Wouldn't MyMat now point to the vector I'm looking for? I was assuming when you passed in pointers to an object, you could modify that object within the function, if not I've made a huge mistake /GOB

Vinterstum
Jul 30, 2003

bobua posted:

Okay, I did this before you guys posted, and I'm not getting why it wouldn't work...

Wouldn't MyMat now point to the vector I'm looking for? I was assuming when you passed in pointers to an object, you could modify that object within the function, if not I've made a huge mistake /GOB

No, in this case you'd be overwriting whatever memory the uninitialized MyMat pointer is pointing to (and likely crash). You need to have an actual object to assign to:

code:
std::vector<Mat> MyMat;
FixGlyphs(...,..., &MyMat);
EDIT: Just to clarify: The above will work, but you're still doing a completely redundant copy as you're still allocating an std::vector on the stack, then copying that into MyMat. Just push your glyphs into "MyMat" directly, rather than going via a temporary vector.

Vinterstum fucked around with this message at 00:46 on May 29, 2013

bobua
Mar 23, 2003
I'd trade it all for just a little more.

Vinterstum posted:

No, in this case you'd be overwriting whatever memory the uninitialized MyMat pointer is pointing to (and likely crash). You need to have an actual object to assign to:

code:
std::vector<Mat> MyMat;
FixGlyphs(...,..., &MyMat);
EDIT: Just to clarify: The above will work, but you're still doing a completely redundant copy as you're still allocating an std::vector on the stack, then copying that into MyMat. Just push your glyphs into "MyMat" directly, rather than going via a temporary vector.

I tried that, but when I tried to do MyMat.push_back or *MyMat.push_back intellisense says 'expression must have class type'

mobby_6kl
Aug 9, 2009

by Fluffdaddy

karoshi posted:

Correct. Optimization priority list:
* cache
* cache
* cache
:words:
...


Alright, thanks! The acceleration structure of course comes first, the whole talk about cache basically started from trying to explain the performance difference between two processors. I was thinking of using an octree as I'm familiar with quadtrees, but what could be better here, a kd-tree perhaps?

Vinterstum
Jul 30, 2003

bobua posted:

I tried that, but when I tried to do MyMat.push_back or *MyMat.push_back intellisense says 'expression must have class type'

Assuming MyMat is is the name of the parameter to FixGlyphs and it's a pointer type, try MyMat->push_back(glyph) or (*MyMat).push_back().

I think at this point I'd really recommend picking up a C++ textbook though, and focus on pointers/references and stack vs. heap. No offense, but it feels like you're trying to do something a bit over your current C++ level.

bobua
Mar 23, 2003
I'd trade it all for just a little more.

Vinterstum posted:

Assuming MyMat is is the name of the parameter to FixGlyphs and it's a pointer type, try MyMat->push_back(glyph) or (*MyMat).push_back().

I think at this point I'd really recommend picking up a C++ textbook though, and focus on pointers and stack vs. heap. No offense, but it feels like you're trying to do something a bit over your current C++ level.

drat it, I didn't bother with the error because I just assumed it didn't work like that, first link on google is a recommendation to use -> which I 'knew about' from the book I'm reading but hadn't run into needing it yet.

No offense taken, I am way over my head. It's just for fun though, and working on a random program that isn't interesting to me would just make me move on to something else. Appreciate the help.

FlapYoJacks
Feb 12, 2009
There's entirely too many colons in this thread. As a C programmer that makes me sad. :smith:

astr0man
Feb 21, 2007

hollyeo deuroga

ratbert90 posted:

There's entirely too many colons in this thread. As a C programmer that makes me sad.

I feel the same way buddy :hfive:

Xerophyte
Mar 17, 2008

This space intentionally left blank

mobby_6kl posted:

Alright, thanks! The acceleration structure of course comes first, the whole talk about cache basically started from trying to explain the performance difference between two processors. I was thinking of using an octree as I'm familiar with quadtrees, but what could be better here, a kd-tree perhaps?

This maybe should move into the graphics thread at this point. Anyhow, by all means, start with an octree. They're the easiest structure to implement and going from checking a million triangles to checking a hundred with an octree is more of an improvement than potentially going from checking a hundred to checking ten by using something more optimal.

What you ideally you want is to use a structure that has cells of variable size in order to use heuristics (specifically, the surface area heuristic) to select better splitting points than always splitting in the middle like an octree. Octrees tend to fit badly to where the geometrical complexity of a scene is: for instance, imagine that you're rendering a mostly empty room save for a small geometrically complicated statue on a table somewhere in it. The octree will cheerfully divide the entire region of space near the statue into finer and finer chunks and any ray that even passes within the same quadrant (err. octant?) has to traverse a decent depth, but the ideal behavior is to construct the structure so that almost the first thing tested is if a ray comes close to the statue (within the bounding box, say). Discarding the complicated regions early in a trace like that can lower the average traversal depth by a lot. kd-trees work well for this and are fairly simple to implement and a simple AABB hierarchy (which a kd-tree is basically a special and more compressible case of) is also pretty reasonable.

For reading, Ingo Wald's phd thesis has a chapter on kd-tree construction and traversal which is pretty detailed, it's what I used first time I implemented this stuff. Googling for a bit got me to some slides on acceleration structures which cover the relevant bits with pretty pictures as well as why the surface area heuristic is good for you. The slides make BVHs sound a lot more limited than they actually are though, for some reason.

FlapYoJacks
Feb 12, 2009

astr0man posted:

I feel the same way buddy :hfive:

Why can't people just use enums and call it good? :smith: Just ignore the vast libraries that make life easy for you in C++!

Slurps Mad Rips
Jan 25, 2009

Bwaltow!

ratbert90 posted:

Why can't people just use enums and call it good? :smith: Just ignore the vast libraries that make life easy for you in C++!

Use enums for everything!

code:
enum class which {
  one,
  two,
  three
}

void cxx11_owns (which) { }

int main () {
  cxx11_owns(which::one);
}
Wait a second.

karoshi
Nov 4, 2008

"Can somebody mspaint eyes on the steaming packages? TIA" yeah well fuck you too buddy, this is the best you're gonna get. Is this even "work-safe"? Let's find out!

Xerophyte posted:

Not that cache isn't important, but you implement an acceleration structure so that you can render a scene with a million triangles by doing collision tests with 4 triangles and 25 planes per trace. Less thrashing the cache is a nice side effect but in optimization its a far distant second to just improving the algorithmic efficiency of the intersection search. This is also why the most significant potential improvement after implementing an octree is implementing something faster than an octree -- octrees build fast but traverse (comparably, it's still an exponential improvement over nothing) slow.

As for actually helping the cache cohere, the main thing to bear in mind is that packing data into minimal space matters. Rays will either cohere or not depending on the scene (usually not, in path tracing at least) and not much can be done about that. However, using an octree that takes 8 bytes of storage per node instead of 32 bytes means fitting 4 times as much of it in cache and that makes cache hits during traversal correspondingly more likely. This is also why texture compression (or at least not storing all textures as HDR floats because now you can) is still relevant when working with 40 GB of RAM on a render cluster rather than what happens to be available on some guy's GPU.

Aside: we actually have a couple of billion-triangle scenes that take up 40 GB of RAM at work. Industrial design people: they really like their tiny details.

I agree. I assume everybody knows that algorithmic optimization (from O(n**3) to O(n**2), or whatever) is the best optimization. It's when trying to optimize further, once the algorithm stands, that people tend to forget about cache. Or at least I did :v:. Sometimes sorting your data costs 1.5% run-time and gives you a 70% boost.
I was surprised when I read some VFX's guy comments about the new raytracing PCIe boards https://www.caustic.com/series2/index.html Imagination is launching. The top one has 16GB, apparently VFX people love huge scenes, too.

FlapYoJacks
Feb 12, 2009

SAHChandler posted:

Use enums for everything!

code:
enum class which {
  one,
  two,
  three
}

void cxx11_owns (which) { }

int main () {
  cxx11_owns(which::one);
}
Wait a second.


I was thinking:

code:
typedef enum 
{
   FARTS,
   GAS
} BUTT_OBJECT
extern BUTT_OBJECT ButtObject;
Now you have OO C!

BirdOfPlay
Feb 19, 2012

THUNDERDOME LOSER
Staring at my code and I can't help but feel like I'm doing something stupid. For anybody not familiar with the SQLite API (most everybody?), a pointer to struct sqlite3 (db) is closed by the function sqlite3_close(), mind blowing stuff. It returns an error code; SQLITE_OK means it closed properly, anything else and something is preventing it's closure, like a prepared statement that hasn't been finalized.

C++ code:
dbm_SQLiteDatabase::~dbm_SQLiteDatabase(void)
{
	int err = sqlite3_close(db);

	if (err != SQLITE_OK) 
	{
		// And now we're good and rightly hosed. The database isn't closed, but the object using it is gone
	}
}
Is my comment correct? Would the safer alternative be to open and close the connection only during function calls that require doing stuff with the connection? Or, gasp, to actually try to figure out what's going on?

ratbert90 posted:

Why can't people just use enums and call it good? :smith: Just ignore the vast libraries that make life easy for you in C++!

I was using enums so that I could communicate SQL data types between classes, but I switched it over to #define constant bits so that I can whip up masks for combining data types if they're unsupported by the library.

MrMoo
Sep 14, 2000

That's why Google added sqlite3_close_v2() .

ephphatha
Dec 18, 2009




I was using enums, then I needed to associate a string with an enum value for human readable file I/O...

code:
class Type {
public:
  static const QList<QString>& Types(void);

  Type(int value = 0) throw (std::out_of_range);

  Type(const QString &name) throw (std::invalid_argument);

  operator QString() const;

  int Value() const;

  bool operator==(const Type &rhs) const;
  bool operator!=(const Type &rhs) const;

private:
  static QList<QString> types;

  int value;
 
  static void InitialiseStaticData();
};
(If anyone knows of a better way I'm all ears)

BirdOfPlay
Feb 19, 2012

THUNDERDOME LOSER

MrMoo posted:

That's why Google added sqlite3_close_v2() .

I coulda sworn that the v2 functions require you to use v2 throughout or something, which provides functionality I mostly do not need. To be fair, this is only one of those things that I'm fretting over to keep it safe and not an issue I've run into yet.

That Turkey Story
Mar 30, 2003

Ephphatha posted:

I was using enums, then I needed to associate a string with an enum value for human readable file I/O...

<snip>

(If anyone knows of a better way I'm all ears)

Just have to_string and from_string functions for the enum and/or overload stream extraction and insertion operators -- no need for a separate type to encapsulate it. Also, old-style exception specifications are deprecated, use noexcept specifications instead.

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!
I was wondering about good practices when trying to assert for memory leaks in tests, particularly when those tests are using 3rd-party code. The stuff I have tried generally compares two snapshots of the heap before and after something runs, and I usually use a closure to encapsulate the test so anything that is on the stack gets a chance to leave scope. Something like this:

code:
SOME_TESTING_FRAMEWORK("Stuff")
{
   StartHeapChecking();
   {
      Declare some stuff
      Do things
      Assert them
      explicitly delete what needs to be deleted
   }  // Stuff on stack will destruct here
   CompareHeapProfilesAndSpewLeaks();
}
I usually end up with tons of gunk outside of my immediate code. If I'm using OpenCL, I'll see stuff there. Or maybe with OpenGL I'll see other stuff. I don't know if I've seen Boost show up, but there is some Microsoft stuff. In the past I've just figured out how to get a blacklist into the tool to ignore some of that, but I'm wondering if this is unwise. Is it usual to see that kind of noise from supporting libraries? I was thinking maybe I'm not calling some cleanup code related to them that I really need to do.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
You're probably going to get a bunch of false positives from stuff that's lazy-initialized but is essentially supposed to persist for the life of the process.

One thing you could try is to run the test once, take a snapshot, and then run the test again and take another snapshot - anything new in between those two snapshots is more likely to be an actual leak than just lazy initialization or whatever.

ephphatha
Dec 18, 2009




That Turkey Story posted:

Just have to_string and from_string functions for the enum and/or overload stream extraction and insertion operators -- no need for a separate type to encapsulate it. Also, old-style exception specifications are deprecated, use noexcept specifications instead.

Thanks for the advice, however I found out that Qt provides a QMetaEnum object that can be used to get details about an enum. So my serialisation code ended up looking like:

code:
// Reading
val = json[this->type.first];

if (!val.isUndefined() && val.isString())
{
  bool success;
  int enumVal = Interval::staticMetaObject.enumerator(Interval::staticMetaObject.indexOfEnumerator("Type")).keyToValue(val.toString().toStdString().c_str(), &success);
  if (success)
  {
    this->ChangeType(static_cast<Interval::Type>(enumVal));
  }
}
code:
// Writing
obj[this->type.first] = QString(Interval::staticMetaObject.enumerator(Interval::staticMetaObject.indexOfEnumerator("Type")).valueToKey(this->type.second));
And while it looks loving awful I only have to worry about that code in those two places, the rest of the time I can use standard enum value comparisons. Saves me having to remember to change the string constants when I rename the enum constants.

hooah
Feb 6, 2006
WTF?
I'm having more problems similar to ones I had before. Making a new class "student", with private data my_name, my_qualityPoints, and my_credits. Most of the errors I'm getting are while MSVC is compiling student.cpp. The first is "iostream(10): error C2143: syntax error : missing ';' before 'namespace'". I get four "syntax : identifier 'my_credits'" errors when referencing my_credits in the following function header (but not in other locations):
code:
string student::standing() const
{
	if my_credits>=90.0
		return "Senior";
	if my_credits>=60.0
		return "Junior";
	if my_credits>=30.0
		return "Sophomore";
	if my_credits<30.0
		return "Freshman";
}
The last error comes when compiling the test driver program, and it's saying it can't find a header file again. I've made sure I only have one copy of the relevant .h and .cpp files for this particular header, and they're included in the project.

Any help with any of these?

raminasi
Jan 25, 2005

a last drink with no ice
if statements should have parentheses around their conditions, but that's not necessarily your only problem.

Sang-
Nov 2, 2007

hooah posted:

I'm having more problems similar to ones I had before. Making a new class "student", with private data my_name, my_qualityPoints, and my_credits. Most of the errors I'm getting are while MSVC is compiling student.cpp. The first is "iostream(10): error C2143: syntax error : missing ';' before 'namespace'". I get four "syntax : identifier 'my_credits'" errors when referencing my_credits in the following function header (but not in other locations):
code:
string student::standing() const
{
	if my_credits>=90.0
		return "Senior";
	if my_credits>=60.0
		return "Junior";
	if my_credits>=30.0
		return "Sophomore";
	if my_credits<30.0
		return "Freshman";
}
The last error comes when compiling the test driver program, and it's saying it can't find a header file again. I've made sure I only have one copy of the relevant .h and .cpp files for this particular header, and they're included in the project.

Any help with any of these?

i think, in the class in the header you've not finished it with a semi-colon (after the closing brace)

BirdOfPlay
Feb 19, 2012

THUNDERDOME LOSER
Umm, what about the snippet around namespace? That might help us identify your compiler error for that one. Scratch that, do you have any code above your include statements? Actually, just post the entire snippet for those includes (and everything above) while you're digging around, because your error states that it's missing a semi-colon inside of iostream! Now, and this just may be me, I've never seen a compiler's core library have a little type like forgetting a semi-colon before. Sang- may have nailed it.

Also,

hooah posted:

Edit: Turns out I had the wrong grid.cpp file :blush: File locating is apparently going to be the bane of my existence with coding.

Umm, how do and why would you have multiple copies of the same file floating around? :psyduck: this is something that you should correct.

hooah
Feb 6, 2006
WTF?

BirdOfPlay posted:

Also,


Umm, how do and why would you have multiple copies of the same file floating around? :psyduck: this is something that you should correct.

Before I knew what I was doing with file arrangement (if I even do now), I moved copied the original from its folder to that folder's parent, which is my project folder. Then I changed one of those files.

As for the other stuff, I appreciate the quick replies, but I'll have to wait until I can sit down with this again. In the meantime, I have 14 hours of travelling to look forward to!

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!

Jabor posted:

You're probably going to get a bunch of false positives from stuff that's lazy-initialized but is essentially supposed to persist for the life of the process.

One thing you could try is to run the test once, take a snapshot, and then run the test again and take another snapshot - anything new in between those two snapshots is more likely to be an actual leak than just lazy initialization or whatever.
I assume you mean I could diff a snapshot between a run I thought was okay versus a later one for the sake of nailing down regressions. I can't imagine if I was running the test for the first time that I'd necessarily nail any leaks that already happened. I'm just trying to understand the implications of what you wrote. I guess it confirms what I suspected; one can normally expect little bits and pieces like that.

Adbot
ADBOT LOVES YOU

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

Rocko Bonaparte posted:

I assume you mean I could diff a snapshot between a run I thought was okay versus a later one for the sake of nailing down regressions. I can't imagine if I was running the test for the first time that I'd necessarily nail any leaks that already happened. I'm just trying to understand the implications of what you wrote. I guess it confirms what I suspected; one can normally expect little bits and pieces like that.

What I was suggesting is that you run the test once to completion, take a heap snapshot, and then (on the same heap) run all your tests again and take a second snapshot afterwards. The idea is that the first test run forces all the lazy initialization to happen, so comparing the two snapshots allows to see everything that's leaking more memory every time it's run.

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