Как повторно присвоить 'этот' указатель в функции элемента объекта?

У меня есть интересный вопрос об указателях C++.

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

Таким образом, это - ситуация. У меня есть класс C++ TestClass, и у меня есть указатель этого типа:

TestClass* A = new TestClass();

Среди прочего TestClass имеет эту функцию:

void TestClass::Foo(){
    TestClass* B = new TestClass();
    ...
}

Эта функция создает объект B того же типа и заполняет его с некоторыми данными.

В конце этой функции я хочу, чтобы указатель указал на объект B. Где угодно вне этой функции это было бы похоже A=B; в этой функции это могло быть похожим this = B
Но поскольку Вы знаете, что не можете повторно присвоить "этот" указатель.

Возможные решения:

  1. Скопируйте память:

    memcpy(this, B, sizeof(TestClass));
    

    Этот метод работает правильно. Функция копирует каждый бит объекта B в объект A.
    Проблема: если TestClass является большим объектом (и это), он создает значительные издержки в производительности для нескольких вызовов Foo.

  2. Возвратите указатель B из функции и сделайте что-то вроде этого

    Temp = A;
    A=A->Foo();
    freeMemory(Temp);
    

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

Таким образом, вопрос, как я могу сделать this = B из функции членства, не копируя целые объекты?

6
задан Michael Myers 12 January 2010 в 15:39
поделиться

7 ответов

Внутри вашего Функция, вы можете сделать

*this = B;

, которые делают красивую одну и ту же копию операции.
Или вы также можете объявить

Foo(TestClass &X);

и переназначить X-адрес внутри.

6
ответ дан 8 December 2019 в 02:46
поделиться

Проблема в том, что многие указатели, а не только A, могут указывать на старый объект. Этот указатель не A, хотя A содержит его копию. Единственный способ сделать это - 1. переназначить A или 2. создайте новый тип указателя, который добавляет уровень косвенности к объекту, чтобы его можно было заменить без ведома пользователя.

-121--4096582-

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

-121--4096584-

Невозможно. этот определяется стандартом как StartClass * const .

Чтобы понять, почему, подумайте об этом коде:

int main() {
   TestClass A;
   A.Foo();
   return 0;
}

A находится в стеке. Как сделать объект в стеке «ссылающимся» на что-то другое?

4
ответ дан 8 December 2019 в 02:46
поделиться

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

class TestClass
{
private:
  TestClassData* m_data;

};

void TestClass::Foo()
{
  TestClassData* B = new TestClassData();
  ... 
  delete m_data;
  m_data = B;
} 

Просто убедитесь, что ваш оператор == возвращает true, если содержимое m_data равно.

13
ответ дан 8 December 2019 в 02:46
поделиться

как я могу это сделать = B

Ты не можешь.

Одно из рабочих решений: memcpy(this, B, sizeof(TestClass)); этот метод работает корректно.

Если TestClass не является POD, то эта функция не работает. Например, нельзя использовать memcpy объекты с виртуальными функциями. Вы взорвете флэшку.

7
ответ дан 8 December 2019 в 02:46
поделиться

Проблема в том, что многие указатели, а не только а, могут указывать на старый объект. Этот указатель не является, хотя A содержит копию ее. Единственный способ сделать это 1. Переназначить a, или 2. Сделать новый тип указателя, который добавляет уровень подражания на ваш объект, чтобы вы могли заменить его без того, кого знают.

-121--4096582-

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

0
ответ дан 8 December 2019 в 02:46
поделиться

Проблема, связанная с выражением, заключается в том, что оно совпадает с пустой последовательностью, что означает, что если вы это сделаете:

>>> p = re.compile('b*(abb*)*(a|)')
>>> p.match('c').group(0)
''

и поскольку re.match пытается соответствовать началу последовательности, вы должны сказать, чтобы оно соответствовало ей до конца последовательности. просто используйте $ для этого

>>> p = re.compile(r'b*(abb*)*(a|)$')
>>> print p.match('c')
None
>>> p.match('ababababab').group(0)
'ababababab'

ps- возможно, вы отметили, что я использовал r 'pattern' вместо 'образца' больше для этого здесь (первые абзацы)

-121--4594714-

Я реализовал свои собственные расширения WCF для Ninject 2,0, прежде чем узнал, что на Гитубе было это . Моя реализация немного отличается, но я придумал решение для объектов области:

using System;
using Ninject.Activation;

namespace Ninject.Contrib.Wcf {
  /// <summary>
  /// Defines Scope Callbacks for WCF Context.
  /// </summary>
  public class NinjectWcfScopeCallbacks {
    /// <summary>
    /// Defines WCF Context scope.
    /// </summary>
    public static readonly Func<IContext, object> WcfContext =
      ctx => (System.ServiceModel.OperationContext.Current != null
                ? System.ServiceModel.OperationContext.Current.
                    InstanceContext.
                    Extensions.Find<NinjectInstanceContext>()
                : null);

    /// <summary>
    /// Defines WCF Web Context scope.
    /// </summary>
    public static readonly Func<IContext, object> WcfWebContext = 
               ctx => System.ServiceModel.Web.WebOperationContext.Current;
  }
}

Для полноты я использую обратный вызов, определенный выше:

Bind<IHelloWorldService>()
        .To<HelloWorldService>()
        .InScope(NinjectWcfScopeCallbacks.WcfWebContext);

Служба WCF не размещала в WAS, поэтому не уверен, что вы используете WcfWebContext или WcfContext , определенный выше, но Если WebOperationContext работает, то вы все настроены. В противном случае я обнаружил, что все немного сложнее. Следует отметить, что в приведенном выше фрагменте кода используется класс NinâInstureContext , присоединенный к OperationContext . Это написанный мною класс, в котором используется механизм Ninject 2.0 «кэш и сбор», позволяющий детерминированно размещать объекты. В основном класс представляет собой реализацию IExtension < InstureContext > , которая является конструкцией WCF для присоединения почти всего к OperationContext . Этот класс также реализует интерфейс Ninject INotifyWhenDeposed , который обеспечивает поддержку детерминированной утилизации. Вот как выглядит определение класса:

  /// <summary>
  /// Defines a custom WCF InstanceContext extension that resolves service instances
  /// using Ninject.  
  /// <remarks>
  /// The custom InstanceContext extension provides support for deterministic disposal
  /// of injected dependencies and service instances themselves by being hook into 
  /// Ninject's "cache and collect" mechanism (new in Ninject 2.0) for object life cycle 
  /// management.  This allows binding object instances to the lifetime of a WCF context
  /// and having them deterministically deactivated and disposed.
  /// </remarks>
  /// </summary>
  public class NinjectInstanceContext : 
                IExtension<InstanceContext>, INotifyWhenDisposed {
  }

Остальное расширение WCF для Ninject совпадает с на Гитубе. Что в основном происходит, так это то, что создается поставщик экземпляров, который подключается к цепочке «активации» WCF - я не использую их конкретную терминологию, просто как я понимаю вещи. Таким образом, идея заключается в том, что ваш поставщик экземпляра должен предоставить экземпляры запрашиваемого класса службы WCF. Итак, вот где мы используем Ninject для создания экземпляра сервиса. Таким образом, мы также можем активировать и ввести любые зависимости. Поставщик экземпляра в моей реализации завершает ядро Ninject в экземпляре, если NinâInstureContext и присоединяет его к OperationContext . Создание службы затем делегируется этому расширению WCF. Когда провайдеру экземпляра говорят освободить службу, NinâInstureContext , который был присоединен к OperationContext, удаляется, что в способ реализации INotifyWhenDeposed вызывает детерминированное удаление службы (и, возможно, ее зависимостей).

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

-121--3003494-

Проблема заключается в том, что многие указатели, а не только A, могут указывать на старый объект. Этот указатель не A,Хотя A содержит его копию. Единственный способ сделать это - 1. переназначить A или 2. создайте новый тип указателя, который добавляет уровень косвенности к объекту, чтобы его можно было заменить без ведома пользователя.

2
ответ дан 8 December 2019 в 02:46
поделиться

То, что ты делаешь, нехорошо.

Во-первых, у вас есть функция Foo, которая:

  • Создает и сгенерирует новый класс
  • Перенаправит существующий класс на новый класс

Так почему бы просто не изменить существующий класс на тот, который вам нужен?

Тем не менее, вы можете сделать Foo статическим и взять "взять этот вручную":

void Foo(TestClass*& this)
{
    delete this;
    this = // ...
}

Но это так же отвратительно, как и другие ваши решения. Наверное, нам нужно больше контекста, чтобы дать вам лучшее решение.

1
ответ дан 8 December 2019 в 02:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: