Есть ли способ вызвать конструктор с указателем экземпляра класса?

Мы можем вызвать деструктор явно через указатель класса, почему бы не конструктор? Любая идея?

#include <iostream>

class Con {
public:
    Con( int x ) : x( x ) {

    }

private:
    int x;
};

int main() {
    Con* c = new Con( 1 );
    //c->Con( 2 ); //illegal
    c->~Con(); // ok!
    delete c;
}

Спасибо,

Ответ 1

Нет. Вы не можете.

Con* c = new Con( 1 );
//c->Con( 2 ); //illegal

Вы уже вызвали конструктор в выражении new.

К тому времени, когда у вас есть действительный указатель типа Con*, вы уже создали объект. И вызов конструктора на "построенном" объекте даже не имеет смысла. Так почему С++ это допускает?

Ответ 2

Фактически вы можете называть это, просто синтаксис заключается не в вызове метода-члена (из которого деструктор - это особый случай), поэтому он не выполняется с операторами доступа к члену. Скорее вам придется прибегнуть к синтаксису размещения-нового:

Con c;
c.~Con();        // destroy, now c is not a Con anymore
new (&c) Con();  // recreate, now c is a Con again

В частном случае в предложении С++ 0x, которое фактически используется в одном из примеров кода, предусмотрено средство для повторного использования union как другого типа в случае объединения, содержащего элементы, отличные от POD

union U {
   int i;
   float f;
   std::string s;
};

int main() {
   U u;
   new (&u.s) std::string( "foo" );
   u.s.~string();
   u.i = 5;
}

}

Ответ 3

Вам будет легче, если вы не подумаете о конструкторе и деструкторе как о функциях, которые вы вызываете. Вы их не называете. Вы можете создавать или уничтожать объект. И, как часть построения, выполняется тело конструктора. То же самое, как часть уничтожения объекта, выполняется тело деструктора.

Итак, вы можете построить объект в стеке

YourClass variable(constructor_arguments);

и он будет автоматически разрушен, если он выходит из области видимости.

Вы также можете создать объект в куче

YourClass * ptr = new YourClass(parameters);

Чтобы уничтожить такой объект, вы используете оператор delete

delete ptr;

Вы также можете создать объект в некоторой памяти, которую вы предоставили сами (редко требуется)

char * pool = new char[sizeof(YourClass)]
YourClass *ptr = new(pool) YourClass(parameters);

Вы произвольно уничтожаете такой объект, и синтаксис выглядит как функция invokation, но это скорее уничтожение объекта

ptr->~YourClass();

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

delete[] pool;

Итак, ваш вопрос означает "Почему я могу явно уничтожить объект, к которому у меня есть указатель, но я не могу его построить"? Вы не можете, потому что он уже построен.

Вы также можете прочитать С++ Часто задаваемые вопросы Lite

Ответ 4

Нет, вы не можете вызвать конструктор класса так, как вы объяснили, и это потому, что c не указывает на действительный объект типа con.

Ответ 5

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

Ответ 6

Задание конструктора должно вызываться, когда объект создается. Ничего больше. Если у вас был счетчик ссылок, чтобы отслеживать количество объектов, позволяя конструктору вызываться как функция, он помешает счетчику.

Если вы хотите повторно инициализировать или reset объект, вы можете добавить функцию с именем Reset() или Initialize() и вызвать ее из конструктора. Затем вы также можете вызвать Reset() или Initialize() из указателя объекта.

Ответ 7

Есть еще способ:

template <typename T, typename... Args>
using fn_ExternFunctionConstructorType = void(__thiscall T::*)(Args...);

template <typename RetType, typename T, typename... Args>
using fn_ExternFunctionType = RetType(__thiscall T::*)(Args...);

class __declspec(dllexport) CTest
{
public:
    CTest()
    {
        std::cout << 6 << std::endl;
    }
    int bla(int val) { std::cout << val << std::endl; return -1; }
};


int main(int argc, char** argv)
{
    FARPROC pFuncConstructor = GetProcAddress(GetModuleHandle(NULL), "[email protected]@[email protected]");
    FARPROC pFuncBla = GetProcAddress(GetModuleHandle(NULL), "[email protected]@@[email protected]");
    CTest* pTest = (CTest*)malloc(sizeof(CTest));
    (pTest->*reinterpret_cast<fn_ExternFunctionConstructorType<CTest>&>(pFuncConstructor))();
    (pTest->*reinterpret_cast<fn_ExternFunctionType<int, CTest, int>&>(pFuncBla))(99);
    return 0;
}

ОБНОВЛЕНИЕ: убрал второй вызов конструктора

Ответ 8

Ofc вы можете вызвать его из экземпляра объекта, см. этот код:

 #include <iostream>
class foo{
      public :
      int foo_var;
      foo(){
            std::cout<<"foo_var = "<<foo_var<<std::endl;
            }
      };
int main()
{
    foo * f = new foo();
    // set foo_var
    f->foo_var = 10;
    // call constructor by passing object instanse
    foo * f1 = new(f) foo;
    std::cout<<(f==f1)<<std::endl;
    system("pause");
    return 0;
}

второй вывод - "foo_var = 10", поэтому он работает. третий вывод - "истина", затем (f == f1), означающий, что конструктор не выделяет новую память (оператор new делает, но мы передали указатель на него, чтобы он не использовал другой) там вы действительно полезная практика:

#include <iostream>
template <class t>
class smart_pointer{
      t * p; // the real normal pointer
      public :
      smart_pointer()
      {
          p = (t*) malloc(sizeof(t)); // allocate memory 
          try{ 
          new (p) t; // call the constructor 
          } catch (...)  // if it throws any exception
          {
                  free(p); // free p , dont use delete , because it will
                  // call the destroctor calling the destructor will cause 
                  // freeing a not allocated memory that causes a crash
                  throw; // throw the exception what ever it was
          }

      }
      ~smart_pointer(){delete p;}
      t operator = (t val) // assigment operator
      {
               *p = val;
               return val;
      }
      operator t(){ // type casting operator , usually for std::cout
               return *p;
               }
      };
int main()
{
    smart_pointer<int> x;
    x = 10;
    std::cout<<x<<std::endl;
    system("pause");
    return 0;
}

рекомендуется читать "эффективные С++", "более эффективные С++", "эффективные современные С++" книги