2016-01-25 5 views
0

Для определения второй функции функции const, гарантировано ли это безопасно? Похоже, что у него будет бесконечная рекурсия, поскольку я хочу вернуть const, но другая функция, которую я хочу назвать, не является константой.Может ли это вызвать бесконечный цикл?

Работает с g ++, но я беспокоюсь, что это небезопасно.

#include <iostream> 

using namespace std; 

class test { 
public: 
    int* doSomething(int a) { 
     int* someInt = new int(a); 

     return someInt; 
    } 

    const int* doSomething(int a) const { 
     return doSomething(a); 
    } 
}; 

int main() { 
    test a; 

    cout << *a.doSomething(12345) << endl; 

    return 1; 
} 
+3

Этот код вызывает неконстантную версию 'doSomething'. Попробуйте вызвать версию const и посмотрите, как она взорвалась. –

+0

Почему вы не просто инициализируете 'someInt' при его выделении:' int * someInt = new int (a); ' – erip

+0

Я всегда думал, что C++ не позволяет перегружать функции, которые отличаются только по типу возврата .... – Anedar

ответ

2

Не совсем: в @Pete Беккер отметил в комментариях, если бы вы назвали const версией, которая будет рекурсия:

class test { 
public: 
    int* doSomething(int a) { 
     int* someInt = new int; 
     *someInt = a; 
     return someInt; 
    } 

    const int* doSomething(int a) const { 
     return doSomething(a); 
    } 
}; 

int main() { 
    const test a; 
    // You're not in for a good time: 
    a.doSomething(12345); 
    return 1; 
} 

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

От Скотт Майерс Effective C++ - Third Edition:

Когда const и не- const функции-членов имеют по существу идентичной реализации, дублирование кода можно избежать, имея не- const версии называть const версии

Скотт Майерс продолжает предоставлять безопасные средства для этого:

const int* doSomething(int a) const 
{ 
    int* someInt = new int; 
    *someInt = a; 
    return someInt; 
} 

int* doSomething(int a) 
{ 
    return const_cast<int*>(static_cast<const Test&>(*this).doSomething()); 
} 

В не- const версии, есть два слепки: static_cast в основном превращается в thisconst this, где const_cast отбрасывает прочь const -ness возвращения. Это безопасно, потому что для вызова версии не const у вас должно быть не const this.

Однако, если вы просто предоставление доступа к члену, это просто и легче читать только иметь следующее:

class TestAccess; 
class Test 
{ 
    TestAccess& t; 
public: 
    const TestAccess& getA() const { return t; } 
    TestAcess& getA() { return t; } 
}; 
+0

Решение Скотта Майерса прекрасно. Я пытался подумать, можно ли каким-то образом вызвать версию, отличную от 'const', от 'const', что я не думаю, что вы можете. Спасибо, что объяснили это ясно. Одной из проблем было мое непонимание того, как работает метод const: http://stackoverflow.com/questions/34983475/why-is-stdbasic-stringoperator-a-const-method-if-its-also-a-non- const-met? answertab = active # tab-top – Zhro

+0

Любые оговорки о том, что версия 'const' вызывает версию, отличную от' 'constst''? Кажется, работает нормально. – Zhro

+0

Да: функция члена 'const' обещает никогда не изменять состояние объекта, но вы, по сути, вызываете функцию non-'const', которая может изменять состояние объекта. Безопаснее иметь версию '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' 'const' – Tas

0

В этом случае компилятор всегда будет выбирать не const-версию функции, даже не вызывает const. В противном случае компилятор не будет компилироваться, вы торможение констант. Например, я быстро изменил код:

#include <iostream> 

using namespace std; 

class test { 
public: 
    int* doSomething(int a) { 
     int* someInt = new int; 

     *someInt = a; 
     return someInt; 
    } 
    int ax = 10; 
    void somethingElse(int i) 
    { 
     ax = i; 
    } 
    const int* doSomething(int a) const { 
     somethingElse(a); 
     return 0; 
    } 
}; 

int main() { 
    test a; 

    cout << *a.doSomething(12345) << endl; 

    return 1; 
} 

Этот пример не компилируется, потому что вы вызываете константную функцию внутри константной области. Компилятор не позволит вам это сделать.

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

+0

Я знаю, что это утечка памяти. Это всего лишь пример. – Zhro

+0

Из любопытства вашего стиля кодирования является закрывающая скобка 'somethingElse()' с отступом 8 пробелов по определенной причине или это ошибка? – Zhro

+0

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

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