Почему я не должен пытаться использовать “это” значение после того, как “удалят это”?

Ну, я пытался соответствовать ему с кодом ниже:

Для выполнений = 1 и повторения = 1 метод URL самым быстрым большинство раз сопровождаемый каналом. Я выполняю это с некоторой паузой, новой приблизительно 10 раз. Таким образом для одного доступа времени, с помощью URL самый быстрый способ, которым я могу думать:

LENGTH sum: 10626, per Iteration: 10626.0

CHANNEL sum: 5535, per Iteration: 5535.0

URL sum: 660, per Iteration: 660.0

Для выполнений = 5 и повторения = 50 изображение тянет отличающийся.

LENGTH sum: 39496, per Iteration: 157.984

CHANNEL sum: 74261, per Iteration: 297.044

URL sum: 95534, per Iteration: 382.136

Файл должен кэшировать вызовы к файловой системе, в то время как каналы и URL имеют немного служебные.

Код:

import java.io.*;
import java.net.*;
import java.util.*;

public enum FileSizeBench {

    LENGTH {
        @Override
        public long getResult() throws Exception {
            File me = new File(FileSizeBench.class.getResource(
                    "FileSizeBench.class").getFile());
            return me.length();
        }
    },
    CHANNEL {
        @Override
        public long getResult() throws Exception {
            FileInputStream fis = null;
            try {
                File me = new File(FileSizeBench.class.getResource(
                        "FileSizeBench.class").getFile());
                fis = new FileInputStream(me);
                return fis.getChannel().size();
            } finally {
                fis.close();
            }
        }
    },
    URL {
        @Override
        public long getResult() throws Exception {
            InputStream stream = null;
            try {
                URL url = FileSizeBench.class
                        .getResource("FileSizeBench.class");
                stream = url.openStream();
                return stream.available();
            } finally {
                stream.close();
            }
        }
    };

    public abstract long getResult() throws Exception;

    public static void main(String[] args) throws Exception {
        int runs = 5;
        int iterations = 50;

        EnumMap<FileSizeBench, Long> durations = new EnumMap<FileSizeBench, Long>(FileSizeBench.class);

        for (int i = 0; i < runs; i++) {
            for (FileSizeBench test : values()) {
                if (!durations.containsKey(test)) {
                    durations.put(test, 0l);
                }
                long duration = testNow(test, iterations);
                durations.put(test, durations.get(test) + duration);
                // System.out.println(test + " took: " + duration + ", per iteration: " + ((double)duration / (double)iterations));
            }
        }

        for (Map.Entry<FileSizeBench, Long> entry : durations.entrySet()) {
            System.out.println();
            System.out.println(entry.getKey() + " sum: " + entry.getValue() + ", per Iteration: " + ((double)entry.getValue() / (double)(runs * iterations)));
        }

    }

    private static long testNow(FileSizeBench test, int iterations)
            throws Exception {
        long result = -1;
        long before = System.nanoTime();
        for (int i = 0; i < iterations; i++) {
            if (result == -1) {
                result = test.getResult();
                //System.out.println(result);
            } else if ((result = test.getResult()) != result) {
                 throw new Exception("variance detected!");
             }
        }
        return (System.nanoTime() - before) / 1000;
    }

}
27
задан seaotternerd 24 February 2015 в 03:29
поделиться

7 ответов

Причина, по которой вы не можете ничего сделать с указателем после его удаления (этого или любого другого указателя), заключается в том, что оборудование могло (и некоторые старые машины это делали) перехватить попытку загрузки неверный адрес памяти в регистре. Несмотря на то, что это может быть нормально на любом современном оборудовании, в стандарте говорится, что единственное, что вы можете сделать с недействительным указателем (неинициализированным или удаленным), - это назначить ему (либо NULL, либо из другого действительного указателя).

29
ответ дан 28 November 2019 в 04:08
поделиться

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

Вы можете обойти это, взяв копию указателя (в виде целого числа) перед вызовом delete .

37
ответ дан 28 November 2019 в 04:08
поделиться

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

Теперь некоторые из ваших действий точка на может быть явно «безопасной», но трудно сказать, что происходит в любом методе, который вы можете вызвать.

Из сообщения: «не следует проверять его, сравнивать с другим указателем, сравнивать его с NULL, распечатывать его, приведите его, сделайте с ним что угодно »?

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

Теперь, если вы выполняете reintepret_cast, это, вероятно, другая история, и вы, вероятно, могли бы с ней справиться, поскольку переинтерпретация - это просто побитовая интерпретация, без привлечения (насколько я знаю) каких-либо методов звоните.

3
ответ дан 28 November 2019 в 04:08
поделиться

Как уже упоминалось здесь, LINQ позволяет расширить любой запрос, просто добавив к нему дополнительные критерии.

var query = 
  from x in xs 
  where x==1
  select x;

if (mustAddCriteria1)
  query = 
    from x in query 
    where ... // criteria 1
    select x;

if (mustAddCriteria2)
  query = 
    from x in query 
    where ... // criteria 2
    select x;

И так далее. Этот подход работает идеально. Но, вероятно, вы знаете, что компиляция запросов LINQ довольно затратна: например, Entity Framework может компилировать примерно 500 относительно простых запросов в секунду (см., Например, ORMBattle.NET ).

С другой стороны, многие инструменты ORM поддерживают скомпилированные запросы:

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

Но если мы попытаемся использовать здесь этот подход, мы сразу заметим, что наш запрос на самом деле динамический: IQueryable , который мы выполняем каждый раз, может отличаться от предыдущий. Наличие частей запроса там определяется значениями внешних параметров.

Так можем ли мы выполнять такие запросы как скомпилированные, например, без явного кэширования?

DataObjects.Net 4 поддерживает так называемое «логическое ветвление». Это означает, что любое постоянное логическое выражение оценивается во время компиляции запроса, и его фактическое значение вводится в SQL-запрос как истинная логическая константа (то есть не как значение параметра или как выражение, использующее параметры).

Эта функция позволяет создавать различные планы запросов в зависимости от на значениях таких логических выражений. Например, этот код:

  int all = new Random().Next(2);
  var query = 
    from c in Query<Customer>.All
    where all!=0 || c.Id=="ALFKI"
    select c;

будет выполняться с использованием двух разных SQL-запросов и, следовательно, - двух разных планов запросов:

  • План запроса на основе поиска по индексу (довольно быстро), если все == 0
  • План запроса на основе сканирование индекса (довольно медленное), если all! = 0

Случай, когда all == null, SQL-запрос:

SELECT
  [a].[CustomerId],
  111 AS [TypeId] ,
  [a].[CompanyName]
FROM
  [dbo].[Customers] [a]
WHERE(( CAST( 0 AS bit ) <> 0 ) OR( [a].[CustomerId] = 'ALFKI' ) );

Случай, когда all == null, план запроса:

|--Compute Scalar(DEFINE:([Expr1002]=(111)))
   |--Clustered Index Seek(OBJECT:([DO40-Tests].[dbo].[Customers].[PK_Customer] AS [a]), SEEK:([a].[CustomerId]=N'ALFKI') ORDERED FORWARD)

Второй случай (когда all! = Null), запрос SQL:

SELECT
  [a].[CustomerId],
  111 AS [TypeId] ,
  [a].[CompanyName]
FROM
  [dbo].[Customers] [a]
WHERE(( CAST( 1 AS bit ) <> 0 ) OR( [a].[CustomerId] = 'ALFKI' ) );
-- Notice the ^ value is changed!

Второй случай (когда all! = Null), план запроса:

|--Compute Scalar(DEFINE:([Expr1002]=(111)))
   |--Clustered Index Scan(OBJECT:([DO40-Tests].[dbo].[Customers].[PK_Customer] AS [a]))
-- There is index scan instead of index seek!

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

SELECT
  [a].[CustomerId],
  111 AS [TypeId] ,
  [a].[CompanyName]
FROM
  [dbo].[Customers] [a]
WHERE(( @p <> 0 ) OR ( [a].[CustomerId] = 'ALFKI' ) );
--      ^^ parameter is used here

Поскольку SQL Server (как и большинство баз данных) генерирует единственную версию плана запроса для конкретного запроса, в этом случае у него есть единственный вариант - сгенерировать план со сканированием индекса:

|--Compute Scalar(DEFINE:([Expr1002]=(111)))
   |--Clustered Index Scan(OBJECT:([DO40-Tests].[dbo].[Customers].[PK_Customer] AS [a]), WHERE:(CONVERT(bit,[@p],0)<>(0) OR [DO40-Tests].[dbo].[Customers].[CustomerId] as [a].[CustomerId]=N'ALFKI'))

Хорошо, это было «быстрое» объяснение полезности этой функции. Давайте вернемся к вашему случаю.

Логическое ветвление позволяет реализовать его очень просто:

var categoryId = 1;
var userId = 1;

var query = 
  from product in Query<Product>.All
  let skipCategoryCriteria = !(categoryId > 0)
  let skipUserCriteria = !(userId > 0)
  where skipCategoryCriteria ? true : product.Category.Id==categoryId
  where skipUserCriteria ? true : 
  (
    from order in Query<Order>.All
    from detail in order.OrderDetails
    where detail.Product==product
    select true
  ).Any()
  select product;

Пример отличается от вашего, но он иллюстрирует идею. Я использовал другую модель в основном для того, чтобы проверить это (мой пример основан на модели Northwind).

Это запрос:

  • Не динамический запрос,
28
ответ дан 28 November 2019 в 04:08
поделиться

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

2
ответ дан 28 November 2019 в 04:08
поделиться

b / c адрес, к которому это относится сейчас, он не определен, и вы не знаете, что там могло быть ...

1
ответ дан 28 November 2019 в 04:08
поделиться

В многопоточной программе, когда вы удаляете указатель, свободное пространство может быть выделено другим потоком, перезаписывая пространство, используемое этим . Даже в однопоточной программе, если вы не будете очень осторожны с тем, что вы вызываете перед return ing, все, что вы делаете после удаления этого , может выделить память и перезаписать то, что раньше указывалось на это .

В исполняемом файле Microsoft Visual C ++, скомпилированном в режиме отладки, удаление указателя вызывает немедленную перезапись его памяти тестовым шаблоном 0xCC (неинициализированные переменные также инициализируются этим шаблоном), чтобы помочь в выявление ошибок висящих указателей, таких как эта.

Это напоминает мне, когда я исправлял ошибку в онлайн-игре, в которой конструктор объекта Fire удалял самый старый огонь, если общее количество пожаров достигло определенного числа. Удаленный огонь иногда был родительским огнем, создавая новый огонь - бац, ошибка висячего указателя! Только по счастливой случайности эта ошибка взаимодействовала с алгоритмом распределения памяти совершенно предсказуемым образом (удаленный огонь всегда перезаписывался новым огнем таким же образом) - иначе это вызвало бы десинхронизацию между онлайн-игроками. Я обнаружил эту ошибку при переписывании способа распределения памяти в игре. Из-за его предсказуемости, когда я исправил его, я также смог реализовать эмуляцию его поведения для совместимости со старыми игровыми клиентами.

1
ответ дан 28 November 2019 в 04:08
поделиться
Другие вопросы по тегам:

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