Jump to content

  • Log In with Google      Sign In   
  • Create Account

Khatharr

Member Since 24 Apr 2010
Offline Last Active Private

#5307939 Enums and their extendability via mods

Posted by on Yesterday, 05:53 PM

Half-decent hashing can significantly reduce the performance impact of using strings.

 

What you're describing is something that scripting languages are really specifically designed for though. Be careful not to spend months working on patchwork solutions and then decide to embed an interpreter and end up throwing all that work away.




#5307322 Preventing overengeneering

Posted by on 23 August 2016 - 12:13 AM

Over-engineering appears to be cathartic to a sizable population of engineers. Making things that feel more elegant to you can be satisfying, even if it doesn't actually meaningfully improve the project.




#5306989 Win loop errors

Posted by on 21 August 2016 - 02:36 AM

  • Rather than determining the winner twice (once in the loop and once after), why not use an int instead of a bool? The int could be called "winnerID" and a value of zero would indicate that nobody has won yet.
  • p2score increments by 2 every round. You can express that as p2score += 2.
  • What would happen if the scores started at 1 instead of zero?



#5306453 C++ what is in string after std::istreambuf_iterator< char >(sourceFi...

Posted by on 17 August 2016 - 07:37 PM

You seem to keep wanting to break back to C'ish behavior. You'll be much happier if you stick to idiomatic C++ instead. Mixing the two is begging for problems.
#include <string>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <sstream>

#define infile "in.txt"

std::stringstream loadFromFile(const std::string& filename) {
  std::ifstream sourceFile(filename);
  std::stringstream ss;

  if(!sourceFile) {
    ss << "Error opening file [" << filename << "].\n";
    throw std::runtime_error(ss.str());
  }

  ss << sourceFile.rdbuf();
  return ss;
}

int main() {
  try {
    std::stringstream stream = loadFromFile(infile);

    std::string line;
    int lineNum = 1;
    while(std::getline(stream, line)) {
      std::cout << std::setfill('0') << std::setw(6) << lineNum++ << "] " << line << "\n";
    }
  }
  catch(std::exception& e) { std::cerr << e.what() << "\n"; }

  std::cin.get();
}



#5305786 Is it pathetic to never get actually helpful answers here?

Posted by on 14 August 2016 - 01:22 PM

This is your second "everybody hates me I guess I'll go eat rocks" topic in a pretty short span of time.

 

You're either going to do it or you're not.

 

If you're looking for someone to blame then just blame Chubu and then you can go away and not worry about how you failed.

 

Otherwise grow the fuck up and do what you have to do to make it work. Nobody here is responsible for you or for your success. If you want it, you make it.




#5305648 Is this function correct?

Posted by on 13 August 2016 - 12:23 PM

If this isn't something you do often then you could just use std::find instead of writing a function:

#include <algorithm>

bool found = std::find(vec.begin(), vec.end(), val) != vec.end();



#5305405 Estimating development time

Posted by on 11 August 2016 - 06:02 PM

How to estimate development time more accurately:

  1. Get several years of experience.
  2. Plan carefully and comprehensively.
  3. Estimate the length of each task listed in your plan, using your own experience and any available industry data.
  4. Add together the task times to get a reasonable total time.
  5. Multiply by 10.



#5304963 For Loop Max Bug

Posted by on 09 August 2016 - 02:19 PM

What I'm talking about is being able to write a struct/class that would let you do things like this:

rect.x = 4;
rect.right = 12;
cout << rect.width; //prints out 8

You can do this with functions in C++, of course, but it doesn't feel the same. What I want is to be able to declare this way:

struct Rect {
  int x, y, width, height;
  int left   property;
  int right  property;
  int top    property;
  int bottom property;
};

Where the 'property' would make it expect you to define a get/set for the variable something like this:

int Rect::operator right=(int value) { width = value - x; }
int Rect::operator right()           { return x + width; }



#5304528 Multithreaded Game Engine Architecture With Data Oriented Design

Posted by on 07 August 2016 - 02:39 PM

https://www.unrealengine.com/what-is-unreal-engine-4




#5304411 Beginner Question - Good Practice

Posted by on 06 August 2016 - 02:56 PM

Added comments.




#5304400 Beginner Question - Good Practice

Posted by on 06 August 2016 - 02:09 PM

This may give you a more realistic idea of the overhead. Keep in mind that testing should be done in release build without a debugger attached. When viewing the results consider the number of iterations in comparison to the number of allocations/releases in your program. (100 million is a lot.)

#include <iostream>
#include <memory>
#include <chrono>

//this templated struct allows you to create POD (plain old data) objects of arbitrary size
template<size_t SIZE>
struct POD {
  char doota[SIZE];
};

//same idea but with some busywork constructor and destructors
template<size_t SIZE>
class Complex {
public:
  Complex() {
    for(size_t i = 0; i < SIZE; i++) { doota[i] = 1; }
  }

  ~Complex() {
    for(size_t i = 0; i < SIZE; i++) { doota[i] = 0; }
  }

private:
  char doota[SIZE];
};

//here we define some terms for convenience. this use of 'using' is similar to typedef, but easier to read and it works for templates
const size_t LARGE = 1024;
const size_t SMALL = 1;
using LargePOD = POD<LARGE>;
using SmallPOD = POD<SMALL>;
using LargeComplex = Complex<LARGE>;
using SmallComplex = Complex<SMALL>;

//this is a template function that uses manual memory management to create
// and delete 'iterations' number of objects for type T (the type is passed
// in as a template argument at the call site)
template<class T>
void manualMMTest(size_t iterations) {
  for(size_t i = 0; i < iterations; i++) {
    delete new T;
  }
}

//same thing using unique_ptr
template<class T>
void uniqPtrMMTest(size_t iterations) {
  for(size_t i = 0; i < iterations; i++) {
    std::make_unique<T>();
  }
}

//and shared_ptr
template<class T>
void sharPtrMMTest(size_t iterations) {
  for(size_t i = 0; i < iterations; i++) {
    std::make_shared<T>();
  }
}

//this is a high-precision timer class that should be
//fairly simple to understand by reading it
class Timer {
  using moment = std::chrono::time_point<std::chrono::high_resolution_clock>;

public:
  void startFromZero() {
    start = std::chrono::high_resolution_clock::now();
  }

  double getElapsedSeconds() {
    moment stop = std::chrono::high_resolution_clock::now();
    std::chrono::nanoseconds elapsed = stop - start;
    return elapsed.count() / 1000000000.0;
  }
  
private:
  moment start;
};

//this runs a batch of tests using the previously defined functions and prints the results
template<class T>
void doBatch(size_t iterations) {
  Timer timer;
  double seconds = 0;

  timer.startFromZero();
  manualMMTest<T>(iterations);
  seconds = timer.getElapsedSeconds();
  std::cout << "  Manual management: " << seconds << " seconds.\n";

  timer.startFromZero();
  uniqPtrMMTest<T>(iterations);
  seconds = timer.getElapsedSeconds();
  std::cout << "  unique_ptr: " << seconds << " seconds.\n";

  timer.startFromZero();
  sharPtrMMTest<T>(iterations);
  seconds = timer.getElapsedSeconds();
  std::cout << "  shared_ptr: " << seconds << " seconds.\n\n";
}

//and this runs it all
int main() {
  const size_t ITERATIONS = 100000000;

  std::cout << "Begin testing on int (using " << ITERATIONS << " iterations):\n";
  doBatch<int>(ITERATIONS);

  std::cout << "Begin testing on small POD objects (using " << ITERATIONS << " iterations):\n";
  doBatch<SmallPOD>(ITERATIONS);

  std::cout << "Begin testing on large POD objects (using " << ITERATIONS << " iterations):\n";
  doBatch<LargePOD>(ITERATIONS);

  std::cout << "Begin testing on small complex objects (using " << ITERATIONS << " iterations):\n";
  doBatch<SmallComplex>(ITERATIONS);

  std::cout << "Begin testing on large complex objects (using " << ITERATIONS << " iterations):\n";
  doBatch<LargeComplex>(ITERATIONS);


  std::cin.get();
}





#5304387 Beginner Question - Good Practice

Posted by on 06 August 2016 - 01:12 PM

However I meant smart pointers (which deletes itself when the block falls of the stack eg.: shared pointer) being 8-9 times more performance heavy, than manually handled pointers

 

Pics or it didn't happen.

 

 

Obviously the latter, as you described. I totally agree. Btw here is my source for that smart pointer overhead info, tho, he did his own tests: https://youtu.be/obrB-Rei9qA?t=3m44s

 

Saying out loud on an internet video "this is eight to nine times slower" does not constitute testing, even if you say, "after all, I'm more like a C programmer" at the end.




#5304265 Beginner Question - Good Practice

Posted by on 05 August 2016 - 05:00 PM

Pointer deferencing is effectively free if you're not getting goofy with multiple indirection in a tight loop. The CPU has an address lookup unit that does any needed pointer math in the pipeline before the address is actually needed. As long as you don't overload that unit (which is actually hard to do) you should never see a performance impact just from dereferencing.

 

You may be thinking of cache coherency, which is a matter of how you traverse memory rather than how you reach the memory you're traversing. That can be impactful for things like linked lists because over time the list may end up referring to objects that are scattered all over memory, which means that the cache can become worthless and you have to wait on the bus for every node that misses, which is vvveeerrryyy ssslllooowww. Using a container like a vector is very fast in comparison because the data is contiguous in memory, which means that the next element is very likely to be in the cache where it can be accessed quickly and easily.

 

Traversing a linked list can also be expensive because looking through a pointer to find a pointer to find a pointer (etc) can indeed overload the lookup unit.




#5304084 Best Way To Comment Code Without Cluttering

Posted by on 04 August 2016 - 06:04 PM

I almost never comment on the "how" of things, but I occasionally comment on the "why" of things. Most of the times this means a single line of code where needed, about 2% of my lines consist of comments. If you ever get back to your code after a while and you don't remember a thing, the code will still tell you how it works eventually, but it might not always make clear why you chose to do some thing in some particular way.

 

QFE.

 

I generally try to pretend that I'm picking up a project that I was pair programming on a few days before, and I write comments to the other programmer. If the "what" of my code is not obvious then there's a problem with the code and I mark it as needing a rewrite. I leave "why" comments wherever they're useful, which usually happens at the top of a function definition (because madness should be encapsulated). In some cases I comment declarations, and will sometimes include information about guarantees if relevant.

 

It makes me mad when I have to wade through worthless comments to find code, and it irritates me to maintain comments when changing code, so I try not to inflict those kinds of problems on myself or on other people.




#5303009 Xml Parser, C++

Posted by on 28 July 2016 - 05:07 PM

I wrote a partial xml parser (for Tiled's tmx files) with std::regex yesterday, lol. Knowing what fields are going to be (or should be) present makes it a lot easier to work on.






PARTNERS