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
seiken
Feb 7, 2005

hah ha ha

shrughes posted:

Just use `buttIter->->fart()` syntax.

only works on boner arrays

:colbert:

C++ code:
template<typename T>
struct stupid_ptr_base {
  T* t;

  stupid_ptr_base(T* t) : t(t) {}

  T& operator*() const
  {
    return *t;
  }

  T* operator->() const
  {
    return t;
  }
};

template<typename T>
struct stupid_ptr : stupid_ptr_base<T> {
  stupid_ptr(T* t) : stupid_ptr_base<T>(t) {}
};

template<typename T>
struct proxy_base {
  T* t;

  proxy_base(T* t) : t(t) {}

  // Change `&&' to `const' to compile on GCC (allows fuckery).
  T* operator->() &&
  {
    return t;
  }
};

template<typename T>
struct proxy : proxy_base<T> {
  proxy(T* t) : proxy_base<T>(t) {}
};

template<typename U>
struct proxy<stupid_ptr<U>> : proxy_base<stupid_ptr<U>> {
  typedef stupid_ptr<U> T;
  proxy(T* t) : proxy_base<T>(t) {}

  // Change `&&' to `const' to compile on GCC (allows fuckery).
  proxy<U> operator--(int) &&
  {
    return proxy<U>(proxy_base<T>::t->t);
  }
};

template<typename U>
struct stupid_ptr<stupid_ptr<U>> : stupid_ptr_base<stupid_ptr<U>> {
  typedef stupid_ptr<U> T;
  stupid_ptr(T* t) : stupid_ptr_base<T>(t) {}

  proxy<U> operator--(int) const
  {
    return proxy<U>(stupid_ptr_base<T>::t->t);
  }
};

#include <iostream>

struct foo {
  int a;
};

int main()
{
  foo f;
  stupid_ptr<foo> ff(&f);
  stupid_ptr<stupid_ptr<foo>> fff(&ff);
  stupid_ptr<stupid_ptr<stupid_ptr<foo>>> ffff(&fff);

  f.a = 1;
  std::cout << f.a << std::endl;
  ff->a = 2;
  std::cout << f.a << std::endl;
  fff--->a = 3;
  std::cout << f.a << std::endl;
  ffff----->a = 4;
  std::cout << f.a << std::endl;
}

Adbot
ADBOT LOVES YOU

Spatial
Nov 15, 2007

mobby_6kl posted:

I was just dicking around with my (very basic) ray tracer on my laptop, and discovered that it seems to be roughly two times faster than running on the desktop where I originally wrote it. This wouldn't be too surprising since the laptop is like 5 years newer, but the processors are Core2 Q6600 and i7 2620m which should actually have similar overall and FLOPS performance, as far as I could tell from Intel's docs.

Both processors have 2M cache/core and 64-byte cache lines. The i7 supports AVX, but I was using the exact same binary on both machines, compiled with /arch not set using VS2012, optimized for speed and hardcoded to 4 worker threads. This more or less exhausted my ideas for explaining the performance difference. What else could I look into, because the newer processor can't be 4 times faster per core... can it?
The i7 has hyperthreading so it can still run four threads at once even though there are only two cores. It can also dynamically increase its clock frequency when operating under the rated TDP. A Sandy Bridge i7 like that has a world of other architectural improvements over a Q6600; doubling performance per core sounds about right.

The better handling of float denormals might be an especially important performance factor in your raytracer.

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!

mobby_6kl posted:

I was just dicking around with my (very basic) ray tracer on my laptop, and discovered that it seems to be roughly two times faster than running on the desktop where I originally wrote it. This wouldn't be too surprising since the laptop is like 5 years newer, but the processors are Core2 Q6600 and i7 2620m which should actually have similar overall and FLOPS performance, as far as I could tell from Intel's docs.

Both processors have 2M cache/core and 64-byte cache lines. The i7 supports AVX, but I was using the exact same binary on both machines, compiled with /arch not set using VS2012, optimized for speed and hardcoded to 4 worker threads. This more or less exhausted my ideas for explaining the performance difference. What else could I look into, because the newer processor can't be 4 times faster per core... can it?

RAM (DDR2 vs. DDR3, I'm assuming), and the RAM path (integrated memory controller vs. chipset MC). I assume your raytracer quickly degenerates into a clusterfuck of decoherent rays, raping any kind of cache coherency or prefetch heuristic. Congratulations, you wrote a RAM latency benchmark.

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

Still working on baby's first c++ app. I feel like there is a better way to do this and am looking for input(both on method and on the code).

Basically, I have a square in an image, but it's a 'real' image, so the square can be oriented weird, like a diamond, and also with a warped perspective(not actually a square anymore at all). I'm going to apply a warpPerspective function it it, but first I need it's four corners. What I have is it's 'contour' which is just a vector containing all of the points of the square's perimeter. At first, I was just going to do the math and find the highest and lowest X and Y coordinates and call those the corners, but because rounded and 'weird' corners are highly likely, that could throw it off I think(I didn't try it). What I came up with is finding the rotatedRect of the box, then comparing all of the coordinates in my contour to it's corners and grabbing the ones closest.

edit: For clarity, rotatedrect is just a function in this library that finds the smallest rectangle that encloses a set of coordinates.

All estDistance does is produce a number for comparison, it's the distance formula without bothering to find the square root.

code:
	float distance;
	float currentDistance = 99999.9999;
	for(int c = 0; c < 4; c++)
	{
		for (int i = 0; i < contour.size(); i++)
		{
			distance = estDistance(boxCorners[c], contour[i]);
			if(distance < currentDistance) 
			{
				currentDistance = distance;
				betterBoxCorners[c] = contour[i];
			}
		}
		currentDistance = 99999.9999;
	}
Should I be using something better than 99999.9999? max_val(float) or something?
Obvious problems?
I miss c#'s foreach statement, I haven't done any googling yet but is c++'s just much more limited?

FamDav
Mar 29, 2008
If you can use C++11, you can replace these loops with range-based versions ala

code:
for (const auto& point : contour)
And then replace references to contour[i] with point.

If the type of boxCorners is float[4] you can do the same thing, otherwise you can write

code:
for (const auto idx : {0,1,2,3})
And when picking a maximal value, you should use std::numerical_limits<float>::infinity(). You should actually check if your floating point implementation has infinity and use max() if it doesn't, but I assume your computer wasn't made in Soviet Russia.

Implementation-wise, you could use a Hough transform on your contour to find its bounding quadrilateral and use that to find the corners. With your implementation as the angles of the square move away from 90/90/90/90 the corners of the rotatedrect will be nowhere near the actual corners.

EDIT: And this will probably have little to no effect on speed, but I would change the code to loop over every point once and check it against every corner instead of what you have currently.

FamDav fucked around with this message at 19:04 on May 25, 2013

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

FamDav posted:

If you can use C++11, you can replace these loops with range-based versions ala

Implementation-wise, you could use a Hough transform on your contour to find its bounding quadrilateral and use that to find the corners. With your implementation as the angles of the square move away from 90/90/90/90 the corners of the rotatedrect will be nowhere near the actual corners.

EDIT: And this will probably have little to no effect on speed, but I would change the code to loop over every point once and check it against every corner instead of what you have currently.

Ooooh that range based for loop stuff is handy, hadn't learned that yet.

Auh, I misunderstood a rotatedrect, in my mind it created a minimum quadrilateral, not a minimum rectangle. I'll get to work on the hough transform.

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

Why the 'const' in for(const auto &y : x) ?

And why the &? I understand that's the 'address of' operator, but how does using it change what's being done? If you only used y instead of &y, would it be creating a copy of y at some point?

FamDav
Mar 29, 2008
I assume if it says it is a rectangle it is a rectangle, but you should double check. Also, your library may very well implement something which finds a bounding quad so use that instead.

The ampersand in a type declaration means it is a reference, which means that the variable in question refers to the same bit of memory as the variable assigned to it.

The const means that the variable cannot be mutated. This is useful for the compiler help you with not changing values you don't want to be changed, which can be particularly pernicious when you are using references.

And your final assumption is correct, it will instead create copies of each element in the container instead of taking references.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

bobua posted:

Why the 'const' in for(const auto &y : x) ?

And why the &? I understand that's the 'address of' operator, but how does using it change what's being done? If you only used y instead of &y, would it be creating a copy of y at some point?

EDIT: oh, sorry, I forgot you were new to C++. Leaving this up for posterity.

auto is basically template argument deduction against the type of the initializer. The initializer in a for-range loop is the result of dereferencing the iterator (with unary *), so yes, if you don't use &, you'll be copying the element into the induction variable. Whether that's actually a problem depends, of course.

const is mostly communicative here, although if you have some weird custom operator* that doesn't return an lvalue reference (e.g. if it returns a proxy object like std::vector<bool>::iterator), it can be necessary.

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

It's totally cool if I spam this thread with c++ programming questions not worth their own thread, right?

code:
	unsigned char* inp  = img.ptr<unsigned char>(0);
	for(int i=0; i < img.rows; i++)  //for every row 
	{
		inp  = img.ptr<unsigned char>(i);
		for (int j = 0; j < img.cols; j++) //for every column
		{
			if(*inp++ == 0)
			{
				//pixel was black
				gBits[(i)/10][(j)/10]++;
			}
		}
	}
What's the difference between how it's written and replacing 'unsigned char' with 'uchar'? So inp is a pointer to an unsigned char, and .ptr<unsigned char>(i) sets it to point to the first element in img. The 2 loops keep it moving through every element in img? If I was the change unsigned char to another sized datatype, would it just return badly offset data(and eventually overstep or understep img?

I always think I understand pointers, but then I get confused when I see code that puts the *\&'s before or after the variable, or on the datatype instead:( Why is the * on the unsigned char in line one, then prepending inp on line 7? Why does god hate me?

xgalaxy
Jan 27, 2004
i write code

bobua posted:

I always think I understand pointers, but then I get confused when I see code that puts the *\&'s before or after the variable, or on the datatype instead:( Why is the * on the unsigned char in line one, then prepending inp on line 7? Why does god hate me?

Where you place the * and & is a stylistic choice. These are all the same:
code:
char* foo;
char * foo;
char *foo;
Line 1 and 7 are completely different though.
Line 1 is declaring inp to be a pointer to unsigned char whereas line 7 is dereferencing that pointer.

xgalaxy fucked around with this message at 21:06 on May 26, 2013

Dicky B
Mar 23, 2004

bobua posted:

Why is the * on the unsigned char in line one, then prepending inp on line 7? Why does god hate me?
They mean different things. On line 1 * is being used to declare a pointer variable and on line 7 it is being used to dereference a variable.

bobua posted:

What's the difference between how it's written and replacing 'unsigned char' with 'uchar'?
uchar isn't a standard type, but if it's defined by some library you are using then it is probably equivalent to unsigned char.

I can't help with your other question because I have no idea what the type of 'img' is.

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

xgalaxy posted:

Where you place the * and & is a stylistic choice. These are all the same:
code:
char* foo;
char * foo;
char *foo;

and...
char foo*; I assume? just wanna make sure.

That makes way more sense than the convoluted reasoning I had...

Is using the * later on stylistic also?

bool *foo;
if (foo) vs if (*foo) ?

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

Ok, so using the * later 'dereferences' the pointer. So inp in the example would literally return a numerical memory address, while *inp would return what's at that memory address, correct?

If that's the case, is *inp++ incrementing what's at the memory address, or the memory address? it would seem it would be incrementing what's at the memory address, but if that's the case, wouldn't it be changing the Image I'm working with, and not just moving to it's next pixel?

Dicky B
Mar 23, 2004

char foo*; is gibberish.

bool *foo; declares a pointer to an object of type bool.

if(foo) evaluates the value of the pointer (a memory address) as a boolean expression which is probably not what you want to do
if(*foo) dereferences the pointer and actually tests the value of the object (true or false).

nielsm
Jun 1, 2009



bobua posted:

and...
char foo*; I assume? just wanna make sure.
No, that's not legal.
Notice that the only difference between the three you quoted is how the whitespace is distributed.
You moved the star to be after the variable name instead of between the type and variable name.

bobua posted:

That makes way more sense than the convoluted reasoning I had...

Is using the * later on stylistic also?

bool *foo;
if (foo) vs if (*foo) ?
No.

Here you declare foo as a pointer-to-bool. The value of foo is a pointer. Using the prefix * operator on the variable de-references the pointer, so the type of the expression (*foo) is bool.

if(foo) means "if foo is a non-null pointer", while if(*foo) means "if the value pointed to by foo is not false".

(fe:f,b)

Dicky B
Mar 23, 2004

bobua posted:

If that's the case, is *inp++ incrementing what's at the memory address, or the memory address?
It's equivalent to *(inp++), i.e. the pointer is being incremented, not the value it points to.

Also note that the expression inp++ uses the postfix form of the ++ operator, so the pointer will be dereferenced first and then incremented. There is also a prefix form which looks like *(++inp) where the pointer will be incremented first and then dereferenced.

hooah
Feb 6, 2006
WTF?
I'm working on a project from a textbook, and having the same problems as previous projects. My instructor helped me with those, but not very satisfactorily, so I'm hoping someone here can maybe explain what's going on a bit better.

This book comes with a class "grid" that puts out a grid of dots and a mover facing in a cardinal direction (e.g. "v" for south). It only comes with the ability to turn left, and this project has me adding the abilities to turn right and turn around (by just turning left thrice or twice). I followed the instructions, adding "void turnAround();" and "void turnRight();" to the .h file and
code:
void grid::turnAround()
{
	turnLeft();
	turnLeft();
}
(and similarly for turnRight) to the .cpp file. The errors that I encounter on compiling in Visual Studio are C2039s (function is not a member of the class) and C3861s (identifier not found) for the function name.

Here are links to the code on Pastebin:
grid.h
grid.cpp
test.cpp

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed
That code compiles and runs without errors for me with both clang and msvc. I suspect you have multiple copies of grid.h lying around and the wrong one was included.

hooah
Feb 6, 2006
WTF?

Plorkyeran posted:

That code compiles and runs without errors for me with both clang and msvc. I suspect you have multiple copies of grid.h lying around and the wrong one was included.

I just now deleted any extraneous copies of grid.h, removed it from the project, and added it back in, making sure that it's in the same folder as everything else. Now the compiler can't even find the loving file! How? I just added it!

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.

parcs
Nov 20, 2011

hooah posted:

I just now deleted any extraneous copies of grid.h, removed it from the project, and added it back in, making sure that it's in the same folder as everything else. Now the compiler can't even find the loving file! How? I just added it!

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.

I thought IDEs are supposed to make your life easier, not harder :)

tractor fanatic
Sep 9, 2005

Pillbug

hooah posted:

I just now deleted any extraneous copies of grid.h, removed it from the project, and added it back in, making sure that it's in the same folder as everything else. Now the compiler can't even find the loving file! How? I just added it!

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.

Incidentally it doesn't matter to MSVC if you include a header file in the project or not. It only compiles the .cpp files. Including the header files is for your benefit, and maybe Intellisense's.

hooah
Feb 6, 2006
WTF?
Working on a quadratic formula class/program now. I've got the class working fine, but am having a problem with the output of the main program We're given the main program, which includes blocks like this:
code:
cout << "The roots for equation ";
    qe.display();
    cout << "are " << qe.root1() << "(root 1) and " << qe.root2() << "(root 2) " <<endl << endl;
The output that the book (and the professor) wants looks like this:
code:
roots for equation 1x^2 + 0x - 1 are 1(root 1) and -1(root 2)
However, I get a line break after the equation is displayed. How do I prevent that?

Vanadium
Jan 8, 2005

Fix or don't use qe.display().

mobby_6kl
Aug 9, 2009

by Fluffdaddy

Spatial posted:

The i7 has hyperthreading so it can still run four threads at once even though there are only two cores. It can also dynamically increase its clock frequency when operating under the rated TDP. A Sandy Bridge i7 like that has a world of other architectural improvements over a Q6600; doubling performance per core sounds about right.

The better handling of float denormals might be an especially important performance factor in your raytracer.

Thanks. Doubling performance per core is roughly what I'd expect too, actually. What was unexpected is that the i7 was much faster overall, like almost twice as fast with half as many cores. I don't think Hyperthreading can explain this as the overall performance at best doubles when going from a single thread to four.

karoshi posted:

RAM (DDR2 vs. DDR3, I'm assuming), and the RAM path (integrated memory controller vs. chipset MC). I assume your raytracer quickly degenerates into a clusterfuck of decoherent rays, raping any kind of cache coherency or prefetch heuristic. Congratulations, you wrote a RAM latency benchmark.

This makes sense... it seems that in some smaller scenes, the Q6600 is actually somewhat faster, but in the larger scene with many triangles it starts to fall way behind. I'll try to rig up some benchmark to see if there's a sharp drop off once the scene no longer fits into cache.

At the moment I'm naively testing each ray against all objects so implementing an octree or some other acceleration structure should probably be the first priority, optimization-wise. But am I correct in thinking that this would also significantly improve the cache situation, as adjacent rays would likely be tested against the same small subset of objects, thus keeping them cached? Other then that, I'm not really sure what else could be done, since what happens then isn't very predictable.

FlapYoJacks
Feb 12, 2009

hooah posted:

Working on a quadratic formula class/program now. I've got the class working fine, but am having a problem with the output of the main program We're given the main program, which includes blocks like this:
code:
cout << "The roots for equation ";
    qe.display();
    cout << "are " << qe.root1() << "(root 1) and " << qe.root2() << "(root 2) " <<endl << endl;
The output that the book (and the professor) wants looks like this:
code:
roots for equation 1x^2 + 0x - 1 are 1(root 1) and -1(root 2)
However, I get a line break after the equation is displayed. How do I prevent that?

Use a for loop and strlen to find the linebreak and replace it with a \0 instead.

nielsm
Jun 1, 2009



ratbert90 posted:

Use a for loop and strlen to find the linebreak and replace it with a \0 instead.

Wouldn't work.
Notice, the qe.display() function is printing by itself, it doesn't return a string.

Either modify the qe.display() function so it doesn't print, but instead returns an appropriate string, or add another function to the class to do that.

FlapYoJacks
Feb 12, 2009

nielsm posted:

Wouldn't work.
Notice, the qe.display() function is printing by itself, it doesn't return a string.

Either modify the qe.display() function so it doesn't print, but instead returns an appropriate string, or add another function to the class to do that.

Ah, my mind glazed over and for some reason I just assumed he was using cin. my bad. :v:

Vanadium
Jan 8, 2005

Replace the buffer that cout writes to with one of those ostringstream buffers before calling the function. :sun:

Vanadium
Jan 8, 2005

Use dup2 to redirect stdout into a pipe then read from that and

ephphatha
Dec 18, 2009




I've got a question about implicit typecasting/typecast operators.

I have a class "Interval" with the following definition (unnecessary cruft trimmed):
code:
Interval.h
#pragma once
#include <QJsonObject>
#include <QJsonValue>

class Interval
{
public:
  operator QJsonObject() const;

  operator QJsonValue() const;
};

Interval.cpp
#include "Interval.h"

Interval::operator QJsonObject() const
{
  QJsonObject obj;

  // add values to the QJsonObject

  return obj;
}

Interval::operator QJsonValue() const
{
  // QJsonValue provides a QJsonValue(const QJsonObject &) constructor that I'm abusing here.
  return QJsonObject(*this);
}
And it's used like so:

code:
#include <QJsonArray>
#include <QList>
#include "Interval.h"

int main(int, char**)
{
  QJsonArray intervalsToWrite;
  QList<Interval> intervals;
  //populate intervals
  for (QList<Interval>::const_iterator it = intervals.begin(); it != intervals.end(); ++it)
  {
    intervalsToWrite.append(*it); // QJsonArray.Append expects an argument of const QJsonValue&
  }
}
This compiles and seems to run fine, but I'm wondering if there are any problems I'm yet to run across with doing this. Should I be using a different signature for the typecast operators/providing a const cast version for each type as well as/instead of the current version?

hooah
Feb 6, 2006
WTF?

nielsm posted:

Wouldn't work.
Notice, the qe.display() function is printing by itself, it doesn't return a string.

Either modify the qe.display() function so it doesn't print, but instead returns an appropriate string, or add another function to the class to do that.

I just removed an endl from display().

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!

mobby_6kl posted:

This makes sense... it seems that in some smaller scenes, the Q6600 is actually somewhat faster, but in the larger scene with many triangles it starts to fall way behind. I'll try to rig up some benchmark to see if there's a sharp drop off once the scene no longer fits into cache.

At the moment I'm naively testing each ray against all objects so implementing an octree or some other acceleration structure should probably be the first priority, optimization-wise. But am I correct in thinking that this would also significantly improve the cache situation, as adjacent rays would likely be tested against the same small subset of objects, thus keeping them cached? Other then that, I'm not really sure what else could be done, since what happens then isn't very predictable.

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

The primary rays are basically normal rasterization, they can be accelerated by a normal GPU wonderfully, because GPUs are really good at rasterization. Secondary rays are a horrible clusterfuck. Think of the typical scene: a cluster of mirror balls. Their reflections are all over the place, adjacent pixels lose all coherency and all FLOPS become cache misses and RAM waits. This kills GPUs, too. And yeah, not checking all objects vs. your rays will greatly help the primary rays' rasterization cache hit %. It will also accelerate the secondary rays hit detection cost and their cache footprint, allowing a bigger scene to be rendered before the cache gets trashed. Not everything is a mirror ball, there are also flat mirrors, which maintain a little bit of ray coherence.

netcat
Apr 29, 2008
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?

parcs
Nov 20, 2011

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?

I suppose it's because string literals are const.

seiken
Feb 7, 2005

hah ha ha
Don't take me as a language expert, but I would guess it's because, while arrays decay to pointers to their first element, the reverse is not true. "a" has the type char* which you can't assign or initialise an array with in general. The fact that you can initialise arrays this way normally at all (like char array[] = "foo") is, I believe, a special-case exception in the language, that won't work in other settings. (If you change the char name[8] to a std::string it will work.)

Edit: I guess I gave the fact it didn't work too much credit.

Edit: for what it's worth, it doesn't work on the latest GCC either.

seiken fucked around with this message at 21:26 on May 28, 2013

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
Actually, I think it's probably just a bug in your compiler. It works for me with trunk clang. There's no reason that generalized initialization syntax shouldn't permit array initialization from a string literal.

seiken
Feb 7, 2005

hah ha ha
I'm not familiar with how the new brace-initialisation syntax actually works, but I'm pretty sure as soon as you pass a char* into a function then you can't initialise an array with it. vector is obviously using a function to initialise here, so I don't see why this could work. Is there some magic about initializer_list that preserves the string-literal-ness of the literal?

Edit: oh, the structs get constructed before they get passed into the vector constructor, I guess? That makes sense.

seiken fucked around with this message at 21:44 on May 28, 2013

netcat
Apr 29, 2008

rjmccall posted:

Actually, I think it's probably just a bug in your compiler. It works for me with trunk clang. There's no reason that generalized initialization syntax shouldn't permit array initialization from a string literal.

Ah, OK. I see no reason why it wouldn't work either (especially when "regular" array initialization syntax works just fine), though I have no idea about the details behind initializer_list.

Adbot
ADBOT LOVES YOU

Xerophyte
Mar 17, 2008

This space intentionally left blank

karoshi posted:

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

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.

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