2015-01-03 4 views
1

У меня есть простой узел struct, который содержит значение + 2 указателя на следующие/предыдущие узлы.Использование std :: ptrdiff_t для пользовательских типов

template <class T> 
struct node { 

    node<T> *prev = NULL; 
    node<T> *next = NULL; 
    T data;   
}; 

Здесь у нас есть функция, которая добавляет новый узел в конец.

void push_back(T val) {   

    node<T> *n = new node<T>; // create node to hold val 
    n->data = val;    // set node data with val 

    if (node_count == 0) {  

     begins = n;    // begins points to first node   
    } 
    else{ 

     ends->next = n;   // set next in ends 
     n->prev = ends;   // set previous    
    } 

    ends = n;     // update ends 
    node_count++;    // update list size 
}          

В основном мы создаем 100 связанных узлов, каждый из которых имеет уникальное значение int.

for (int i = 0; i != 100; i++){ push_back(i); } 

Вот указатели на первый/последний узел:

node<T> *begins; 
node<T> *ends; 

Проблема начинается при попытке применить арифметику указателей:

std::ptrdiff_t node_sum = ends - begins; 

Как-то node_sum == 528, если я выполните компиляцию x32, затем node_sum == 781.

Почему node_sum не 100?

+0

этот код скомпилирован? в функции 'push_back' нет' begin' и 'end' до тех пор, пока вы не сделаете их глобальными. – Ankur

+1

Нет гарантии о размещении отдельных узлов в списке; первый узел может быть расположен до второго и после третьего. Тип 'ptrdiff_t' предназначен для того, чтобы различать два указателя в гарантированную непрерывную память, что означает два указателя, указывающих на местоположения в одном массиве (или один элемент за пределами массива). Все остальное приводит к неопределенному поведению; любой результат возможен, и все они верны. –

+0

@ ШАН: опубликованный код не будет компилироваться, но источник делает, я взломал подходящие части, чтобы облегчить глаза. – tuk

ответ

3

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

Это означает, что если у вас есть, например,

begin = new node<T>; 
end = new node<T>; 

это не гарантирует, что begin и end будут рядом друг с другом.

Вы можете использовать арифметику указателей только для указателей, указывающих на ту же область памяти, что и массив, иначе у вас есть неопределенное поведение.

4

Ваши узлы не являются частью массива. Каждый из них выделяется отдельно, в любом месте, которое может найти для них распределитель памяти. Вы не можете вычитать их и ожидать какого-либо определенного значения. На самом деле, это неопределенное поведение. Чтобы подсчитать расстояние между узлами в связанном списке, вам нужно выполнить итерацию через него, следуя указателям следующего или предыдущего.

Смежные вопросы