Может ли использование указателей вызвать засорение памяти? - PullRequest
3 голосов
/ 21 января 2012

Предположим, у меня есть эти структуры в c++:

class A{
  public:
    B b;
}

class B{
  public:
    C c;
}

class C{
  public:
    double x;
    double y;
    double z;
    double s;
    function Usize(){
      s  = sqrt(pow(x,2) + pow(y,2) + pow(z,2));
    }
}

Требуется ли для доступа к значениям в c в десять раз больше трафика, чем для создания прямого указателя на c и его использования?В терминах кода (принимая допустимые значения):

double dx = 2*rand()-1;
double dy = 2*rand()-1;
double dz = 2*rand()-1;

a->b->c.x *= dx;
a->b->c.y *= dy;
a->b->c.z *= dz;

if (a->b->c.x > 10) a->b->c.x -= 10;
else if (a->b->c.x <0) a->b->c.x += 10;
if (a->b->c.y > 10) a->b->c.y -= 10;
else if (a->b->c.y < 0) a->b->c.y += 10;
if (a->b->c.z > 10) a->b->c.z -= 10;
else if (a->b->c.z < 0) a->b->c.z += 10;

a->b->c->Usize();

против

double dx = 2*rand()-1;
double dy = 2*rand()-1;
double dz = 2*rand()-1;


C* ac = a->b->c
ac.x *= dx;
ac.y *= dy;
ac.z *= dz;

if (ac.x > 10) ac.x -= 10;
else if (ac.x < 0)  ac.x += 10;
if (ac.y > 10) ac.y -= 10;
else if (Ac.y < 0) ac.y += 10;
if (ac.z > 10) ac.z -= 10;
else if (ac.z < 0) ac.z += 10;

Спасибо.

Ответы [ 3 ]

11 голосов
/ 21 января 2012

Шансов нет.Разницы не будет.

Хотя верно, что цепочка разыменования приведет к большему количеству обращений к памяти, современные компиляторы способны делать именно то, что вы сделали.(То есть преобразуйте ваш первый пример во второй.)

Это связано со стандартной оптимизацией компилятора под названием Устранение общего выражения выражений (CSE).

Имяв значительной степени говорит обо всем.В первом примере a->b->c - это общее подвыражение, которое будет оптимизировано компилятором.Он будет оценен только один раз, результат будет сохранен и повторно использован для всех необходимых ему экземпляров.


Существует ряд ситуаций, которые могут помешать компилятору выполнить такие оптимизации.

  1. Если объявлены какие-либо релевантные переменные volatile, то такая оптимизация недопустима, поскольку переменная volatile требует ее перезагрузки при каждом использовании.
  2. Если какая-либо из релевантных переменных(или потенциально) модифицированы, тогда эта оптимизация не разрешена, поскольку она может привести к другому результату.

В качестве дополнительного примечания ваш второй пример также более читабелен, поскольку имеется разыменование
Поэтому, если бы мне пришлось выбирать, какой из них использовать, я бы все равно пошел со вторым примером.

2 голосов
/ 21 января 2012

В этом конкретном случае хороший компилятор должен быть в состоянии устранить общее выражение и сгенерировать в значительной степени оптимальный код. Так как вы обращаетесь к примитивным типам, a-> b-> c может быть оценен один раз и использован во всем методе.

Вызов C :: USize () или доступ не примитивного типа в «классе C» нарушит этот шаблон и заставит компилятор переоценить a-> b-> c для следующей строки.

a->b->c.x = 10;
a->b->c.Usize();   // <-- Usize() may change a.b so the next line references another B.
a->b->c.y = 5;

Это потому, что компилятор не может на 100% быть уверенным, что вызов метода / оператор не изменяет a, a.b или b.c, поэтому он должен переоценить цепочку, чтобы убедиться.

Я бы почти сказал, что беспокоиться об этом на данном этапе преждевременной оптимизации. Тем не менее, ваш второй пример более читабелен и помогает компилятору не догадываться, если вы вставите какие-либо вызовы методов позже, поэтому я бы пошел на это.

1 голос
/ 21 января 2012

Теоретически это не будет иметь значения .

Любой современный оптимизатор должен переводить точно такой же код.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...