В основном то, что я хочу, это:

class MyClass{
    public:
        MyClass() = default;
    // what should I do?
}

MyClass mc; // compile time error;
auto pmc = new MyClass; //OK
delete pmc; //OK too

Я знаю, что могу сделать это только кучей, скрывая конструктор (теперь не может быть новым вне класса) или скрывая деструктор (теперь не могу удалять вне класса), или скрывая оба. Что если я не хочу вводить какую-то новую именованную функцию и просто хочу старый добрый new и delete? Возможно ли это (даже при взломе)?

4
J. Doe 21 Окт 2017 в 07:29

3 ответа

Лучший ответ

Моя идея «как умный указатель, но не»:

#include <iostream>

class MyClass_ {
  private:
    /**/     MyClass_( void ) { }
    /**/    ~MyClass_( void ) { }
  public:
    void     func( void ) const { std::cout << "Hello" << std::endl; }

    friend class MyClass;
} ;

class MyClass {
  public:
    /**/     MyClass( void ) : p( new MyClass_ ) { }
    /**/    ~MyClass( void ) { delete p; }

    // Tricky implementation details follow...
    // The question in all cases is, who owns the MyClass_ that has been
    // allocated on the heap?  Do you always allocate a new one, and then
    // copy the guts?  (That might be expensive!)  Do you change ownership?
    // Then what about the other MyClass?  What does it point to?
    // Or do you share ownership?  Then you need to ref-count so you don't
    // delete too soon.  (And this whole thing turns into an ordinary
    // shared_ptr<MyClass_>)

    /**/     MyClass( const MyClass &o ) { }
    /**/     MyClass( MyClass &&o ) { }
    MyClass &operator=( const MyClass &o ) { }
    MyClass &operator=( MyClass &&o ) { }

    MyClass_ * operator->( void ) { return p; }
    const MyClass_ * operator->( void ) const { return p; }

  private:
    MyClass_ *p;
} ;

int
main( int, char ** )
{
    MyClass  a;                  // this will be destroyed properly
    MyClass *b = new MyClass;    // this will leak if you don't delete it

    a->func( );
    (*b)->func( );

    return 0;
}
6
Dave M. 21 Окт 2017 в 13:45

Это будет звучать как не то, что вы хотите, но окружить его в другом классе. Таким образом, вы можете обеспечить, чтобы ваше хранилище выделялось из кучи, и хранить такие детали в стороне от вашего пользователя API.

0
jschmerge 21 Окт 2017 в 04:33

Обычный способ - создать конструктор private и добавить некоторую функцию-член static (вы можете назвать ее фабрикой или производящей функцией), которая возвращает указатель.

Так что ваш класс будет выглядеть

class MyClass{
    private:
        MyClass() = default;
    public:
        static MyClass* make() { return new MyClass;  };
    // what should I do?
}

И вы будете кодировать:

 auto mc = MyClass::make();

В другом месте (вместо new MyClass)

И т.д. Однако следует помнить о правиле пяти и рассмотреть возможность использования (в качестве возврата тип вашего MyClass::make) некоторых интеллектуального указателя из <memory> заголовок.

Вы также можете определить свой собственный класс интеллектуальных указателей с его собственными унарными operator -> и operator * и собственным шаблоны переменных, вдохновленные {{X2 }}...

просто хочу старый добрый новый и удали

В подлинном C ++ 11 это осуждается и может считаться плохим стилем. Вам следует избегать использования явно new за пределами вашей библиотеки и использовать какой-либо способ интеллектуального указателя кода.

0
Basile Starynkevitch 21 Окт 2017 в 05:10