2011-07-24 5 views
4

Примечание: Чтобы уточнить, речь идет не об использовании restrict ключевого слова в целом, но конкретно о его применении к функциям-членам, как описано here.ограничить спецификатор на функции-члены (ограничить этот указатель)

GCC позволяет использовать __restrict__ (ГНУ ++ эквивалент restrict C99) в классификаторе на функции-члена, эффективно делая this ограничение квалифицированного указателя в пределах области видимости функции. Где говядина?

Большинство функций-членов работают с другими членами, обращаясь к ним через this, что является T* const (и обычно неустановленным). Для того, чтобы this был, возможно, псевдонимом, в какой-то мере должен был использоваться второй указатель на тип в функции-члене, и он должен был откуда-то исходить.
Это ситуация, которая регулярно встречается с функциями, не являющимися членами, такими как, например, все двоичные операторы или любая другая свободная функция, которая принимает по крайней мере два указателя или ссылки одинакового нетривиального типа. Однако эти функции не имеют this, поэтому они не актуальны.

Оператор присваивания, конструктор копирования, и унарные операторы сравнения приведены примеры функций-членов, где thisможет быть в принципе псевдонимами (так как другой объект передается с помощью ссылки). Поэтому на самом деле имеет смысл назначить для них классификатор ограничений - для компилятора уже должно быть очевидно, что все остальные функции имеют свойство ограничения в любом случае (потому что никогда не существует второго указателя на Т).

Теперь, если, например, вы использовали restrict на operator= вы должны последовательно не проверить для самостоятельного присвоения на всех, потому что вы говорите, что this не псевдонимы в рамках этой функции (и , если это правда, самообслуживание не может произойти).
Очевидно, это то, о чем вы не можете знать заранее, и это тоже не имеет смысла.

Итак, что было бы случаем, когда на самом деле нужно было бы дать функции-члену классификатора ограничений и где это имеет смысл?

+0

Я не думаю, что это имеет смысл сделать это. Что именно вы бы сгладили с помощью 'this' - это не сплошной массив одного типа? – Anycorn

+0

@Anycom: Если класс имеет элементы данных, любой совместимый указатель может быть псевдонимом элемента данных. – MSalters

ответ

3

Либо мне что-то не хватает, либо ваш вопрос не имеет смысла. this не , что отличается от любого другого аргумента функции-члена, так почему вы удивлены тем, что GCC позволяет применить к нему restrict?

Что касается применения его к оператору присваивания, вы справедливо указываете, что это устранит необходимость явного теста самонаведения. Тогда вы говорите:

Очевидно, что это то, что ты не можешь знать заранее

Но это всегда верно, когда вы используете restrict для чего-нибудь. Например, кто-то может решить позвонить memcpy с перекрывающимися областями памяти; вы «не можете заранее знать», что они этого не сделают. Но объявление restrict для аргументов memcpy означает , они совершили ошибку, если они делают. Точно так же, если вы объявляете оператор присваивания restrict, вы сделали ошибку для того, чтобы кто-то сам назначил объекты этого класса. В этом нет ничего таинственного или противоречивого; это лишь часть семантики restrict, которая накладывает определенные ограничения на остальную часть вашего кода.

Я также не знаю, почему вы считаете невозможным, чтобы функция-член принимала указатель (или ссылку) на другой объект того же типа. Тривиальный пример:

class Point { 
public: 
    double distance(const Point &other) const; 
}; 

Этот вид вещей растет все время.

Итак, настоящий вопрос: почему вы думаете, что this настолько отличается от любого другого аргумента? Или, если вы предпочитаете, как я полностью потерял вашу точку?

0

Боюсь, что я не понимаю, почему вы говорите о this.

restrict указывает, что указатель не перекрывается с другими. Таким образом, компиляторы могут предполагать, что области памяти, указанные указателями ограничения, не зависят, что позволяет проводить более агрессивные оптимизации. __restrict__ будет гораздо более эффективным, если использовать другие переменные указателя, чем this.

Итак, что было бы случаем, когда кто-то действительно хотел бы дать члену ограничитель и определить его смысл?

Достаточно вспомнить представительный случай использования restrict указателей в memcpy:

void Foo::MyCompute(__restrict__ char* bufA, __restrict__ char* BufB) 
{ 
} 
+0

См. Последние два абзаца [здесь] (http://gcc.gnu.org/onlinedocs/gcc/Restricted-Pointers.html#Restricted-Pointers). Я знаю об использовании 'ограничений' для параметров функции или внутри блоков, что, конечно, совершенно ясно. Мой вопрос заключается в том, чтобы дать эту ограниченную квалификацию (как описано в связанной документации), что, похоже, не имеет для меня никакого смысла. – Damon

1

Ссылки вы вывесили интересно. Не будет твердого использования для использования restrict на this.Как вы упомянули в своем вопросе, конструктор копирования , operator = могли быть потенциальными кандидатами; но компилятор может позаботиться о них.

Но следующий случай может быть интересно

struct A 
{ 
    //... 
    void Destroy (A*& p) __restrict__ 
    { 
    delete this; 
    p = 0; 
    p++; 
    } 
}; 

Теперь использовать случай может быть;

A **pp = new A*[10]; 
for(int i = 0; i < 10; i++) 
    pp[i] = new A; 
//... 
A* p = pp[0]; 
for(int i = 0; i < 10; i++) 
    p->Destroy(p); 
delete[] pp; 

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

+0

Хех, забавный пример, хотя я думаю, что это даже не «необычный», а скорее то, чего можно было бы избежать, и для того, чтобы быть несколько неочевидным и иметь странную семантику. Семантика будет несколько похожа на «с любым _different_ указателем на объект, о котором я утверждаю, что это не мой объект, уничтожить _my object_ в любом случае и изменить указатель на какой-то другой объект». – Damon

+0

@ Дамон, это правильно; но компилятор не может различаться между очевидными и неочевидными. В любом случае, ограничение указателя 'this' не имеет для меня никакого смысла. Посмотрите, есть ли у кого-то лучший ответ. – iammilind

0

Добавление этого в качестве ответа, потому что оно, вероятно, лучше подходит как таковое (это своего рода ответ и на самом деле не принадлежит к вопросу, а также немного для комментария).

Подумав об ответе Немо в течение долгого времени, я считаю, что наша интерпретация самонаведения может быть несколько неправильной (хотя Немо был более правильным, чем мой). Как правильно указал Nemo, наличие ограниченного класса this фактически означает, что наличие сглаживания является программной ошибкой. Не больше, не меньше.

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

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

2

Я верю, что вы, ребята, отсутствуете, состоит в том, что аргумент функции-члена также может содержать псевдоним частей или объект. Вот пример

struct some_class { 
    int some_value; 

    void compute_something(int& result) { 
     result = 2*some_value; 
     ... 
     result -= some_value; 
    } 
} 

Можно было бы ожидать, что для компиляции в

*(this + offsetof(some_value)) -> register1 
2*register1 -> register2 
... 
register2 - register1 -> result 

Этот код, к сожалению, было бы неправильно если кто-то передает ссылку на some_value результата. Таким образом, компилятору действительно необходимо создать следующее:

*(this + offsetof(some_value)) -> register1 
2*register1 -> register2 
register2 -> result 

... 
*(this + offsetof(some_value)) -> register1 
result -> register2 
register2 - register1 -> register2 
register2 -> result 

который, очевидно, менее эффективен. Обратите внимание, что если compute_something является строковым, компилятор имеет no способ узнать, может ли результат быть псевдоним some_value или нет, поэтому он имеет, чтобы принять наихудший случай, независимо от того, нет ли он умного или немого. Таким образом, существует определенное и очень реальное преимущество для ограничения, даже если оно применяется к этому указателю.