новое с исключением с Microsoft - PullRequest
1 голос
/ 13 марта 2010

Поскольку я пишу для Windows и Linux, у меня целый ряд проблем. В Microsoft Visual C ++ нет заголовка stdint, но для этого я написал свой собственный.

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

MyClass x = new MyClass();

с

#ifdef MSC_VER
if(!(MyClass x = new MyClass())
{
    throw new std::bad_alloc();
}
#else
MyClass x = new MyClass();
#endif

(или что-то эквивалентное), И работает на ОБА MS C ++ и G ++?

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

Ответы [ 3 ]

2 голосов
/ 13 марта 2010

Компилятор Microsoft C ++ почти полностью соответствует стандартам, за исключением, возможно, нескольких неясных вещей. Не выбрасывать исключения в new не входит в их число.

Кроме того, вы не можете написать макрос, который может обнаружить это выражение и обработать его соответствующим образом, если только вы не хотите переписать все ваши варианты использования new (без цели).

1 голос
/ 13 марта 2010

Самая простая альтернатива - написать собственную реализацию operator new, переопределяя реализацию компилятора по умолчанию (если ваша версия MSVC поддерживает это). Это то, что Роджер также предложил в своем связанном ответе.

Следующая программа иллюстрирует попытку. operator new выделяет память из кучи, используя malloc и free. Если вы выполняете условную компиляцию для G ++ и MSVC, вы также можете использовать HeapAlloc и HeapFree вместо malloc и free для более WinAPI-ориентированного подхода.

#include <iostream>
#include <cstdlib>

void *operator new(unsigned int size) throw (std::bad_alloc) {
    void *ptr = malloc(size);

    if (!ptr)
        throw std::bad_alloc();
    return ptr;
}

void operator delete(void *ptr) throw () {
    free(ptr);
}

// Sample code to test the implementation.
int main(int argc, char **argv) {
    int *values[10];

    for (int i = 0; i < 10; ++i)
        values[i] = new int(i);
    for (int i = 0; i < 10; ++i)
        std::cout << *values[i] << std::endl;
    for (int i = 0; i < 10; ++i)
        delete values[i];
    return 0;
}
1 голос
/ 13 марта 2010

На самом деле, есть простое решение: замените оператор new на оператор, который выдает ошибку при выделении. (Связанный код является стандартным C ++ и может потребовать настройки для вашего компилятора. Вы можете использовать malloc для allocate_from_some_other_source и бесплатную для deallocate_from_some_other_source.)


Старый ответ

(Эти замены требуют изменений в вызывающем коде просто потому, что грамматика C ++ структурирована таким образом, что это неизбежно. Однако они написаны так, чтобы требовать минимальных изменений, чтобы их можно было использовать в качестве логических вставных замен. Настоящее решение - обновление до версии MSVC за последние 7 лет или около того. MSVC6, который, как кажется, вы используете, был фактически выпущен до стандарта C ++ в 1998 году.)

Решить для общего случая сложно, но вот приближение:

struct Thrower { // needs a better name
  void* p;
  Thrower(void* p) : p(p) {
    if (!p) throw std::bad_alloc();
  }
  ~Thrower() {
    if (std::uncaught_exception()) operator delete(p);
    // this is true when the object's ctor throws
  }
  operator void*() const { return p; }
};

int main() {
  int* p = new (Thrower(operator new(sizeof(int))) int(42);
  // int is a placeholder type, but shows you can still pass ctor parameters

  // with a macro becomes:
#define MYNEW(T) new (Thrower(operator new(sizeof(T))) T
  int* p = MYNEW(int)(42);
}

Для известных параметров вы можете избежать макроса и сделать его простым:

template<class T>
T* my_new() {
  T* p = new T();
  if (!p) throw std::bad_alloc();
  return p;
}
template<class T>
T* my_new(T const& value) {
  T* p = new T(value);
  if (!p) throw std::bad_alloc();
  return p;
}

int main() {
  int* p = my_new<int>();
  int* p2 = my_new<int>(*p);
}
...