Почему C++ не реализует конструкцию + вызывание функций в той же строке?

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

MyObject foo.DoBar();

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

Каковы причины, почему те, кто помогает разработать и интегрировать новые возможности в C++ (и возможно другие языки) не позволяют это?

5
задан Anonymous 20 January 2010 в 04:52
поделиться

4 ответа

Невозможно выполнить ! операция на @ head , если она не существует. Сначала необходимо инициализировать его. Вероятно, следует объявить его нулевым .

-121--3509677-

В дополнение к предложению Матчу, вы также можете использовать defined? для инициализации @ head без предупреждения:

if defined? @head
  ...
else
  @head = new_node
end

Нормальный идиом для такого рода вещей является

@head ||= new_node

, который также не вызовет предупреждения, но в этом случае кажется, что вам нужно сделать что-то, если @ head не был определен, и это не idempotent так что | | = не идти на работу очень хорошо в данном случае. | | = также имеет недостаток, заключающийся в том, что быть не удается различить ложные, нулевые или неустановленные значения. Инициализация до nil в инициализации, вероятно, является лучшим выбором.

-121--3509674-

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

MyObject().DoBar();

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

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

15
ответ дан 18 December 2019 в 07:54
поделиться

Вместо strlen () следует использовать strlen _ user () - и следует вызвать его только один раз, и сохранить результат (в противном случае у вас есть потенциальный эксплойт ядра, потому что второй поток userspace может изменить

Также можно использовать strncpy _ from _ user () .

Кроме того, kmalloc выглядит нормально.


(Но на самом деле, как говорит ephemient , следует переосмыслить весь свой подход и использовать аргумент count вместо того, чтобы рассматривать ввод как последовательность).


Поскольку вы не можете полагаться на данные, записанные в файл со строками, заканчивающимися числом, необходимо сохранить параметр длины data _ len рядом с данными . Тогда ваши реализации read / write будут примерно такими:

static char *data = NULL;
static size_t data_len;
static DEFINE_MUTEX(data_mutex);

static ssize_t memo_read(struct file *f, char __user *buf, size_t count, loff_t *f_pos
{
    ssize_t retval = 0;
    char *start;

    mutex_lock(&data_mutex);

    if (!data)
    {
        retval = -EINVAL; /* Or whatever you want to do here... */
        goto out;
    }

    if (*f_pos >= data_len)
        goto out; /* EOF */

    start = data + *f_pos;
    retval = data_len - *f_pos;

    if (retval > count)
        retval = count;

    if (copy_to_user(buf, start, retval))
    {
        retval = -EFAULT;
        goto out;
    }

    *f_pos += retval;

out:
    mutex_unlock(&data_mutex);
    return retval;
}

static ssize_t memo_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
    ssize_t retval = -ENOMEM;

    mutex_lock(&data_mutex);

    if (data)
        kfree(data);

    data = kmalloc(count, GFP_KERNEL);

    if (!data)
        goto out;

    if (copy_from_user(data, buf, count))
    {
        kfree(data);
        retval = -EFAULT;
        goto out;
    }

    *f_pos = count;
    retval = count;
    data_len = count;

out:
    mutex_unlock(&data_mutex);
    return retval;
}
-121--3311457-

я бы держался подальше от использования MAC-адресов. На некоторых аппаратных средствах MAC-адрес может изменяться при перезагрузке. Мы научились очень рано во время наших исследований не полагаться на это.

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

Обязательная оговорка и пробка: компания, которую я соучредил, выпускает лицензионное решение OffSunZero Cobalt . Поэтому вас, вероятно, не удивит, если я рекомендую передать ваше лицензирование на аутсорсинг и сосредоточиться на ваших основных компетенциях.

-121--1849979-

Я думаю, что лучше вопрос, почему он должен? В конце концов:

MyObject foo;
foo.DoBar();

Вряд ли сложнее. Это также более читаемо (хотя очевидно, что это может быть предвзято). Даже если бы вы могли построить-вызов, это, скорее всего, было бы помечено как «плохая вещь». Как бы несколько объявлений в одной строке допустимы, но часто снижают читаемость.

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

В ответ на:

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

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

Не говоря уже о другом варианте:

struct MyObject
{
    MyObject(bool pCallDoBar = true)
    {
        if (pCallDoBar)
            DoBar();
    }

    void DoBar(void)
    {
    }
};

MyObject foo;

Или просто:

MyObject().DoBar(); // destructor called here, though

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

3
ответ дан 18 December 2019 в 07:54
поделиться

Ну вот проблема: что если foo необходимо использовать конструктор не по умолчанию. Теперь это

MyObject foo(arg1, arg2).DoBar();

Это такое грязное и действительно не намного лучше, чем

MyObject foo(arg1, arg2);
foo.DoBar();

, помните: код должен быть легко понятен!

Обратите внимание, что это вроде возможно делать то, что вы хотите, если Dobar возвращает ссылку на * :

MyObject foo = MyObject().DoBar();

с C ++ 0x Перемещение конструкторов, это повлечет за собой немного накладных, но пока Тогда ожидайте ложную копию.

0
ответ дан 18 December 2019 в 07:54
поделиться

В последнем параграфе вы ссылаетесь на комитет по стандартам C++. Он был очень занят, и важные особенности языка действительно отбрасываются, потому что у комитета заканчивается время (например, std::unorddered_map в текущем стандарте и концепциях в предстоящем). Они не заинтересованы в том, чтобы вносить незначительные изменения без веских на то оснований. В дни, предшествующие заседанию комитета по стандартам, Bjarne Stroustrup не был заинтересован в добавлении незначительных функций только ради них.

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

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

Недостатком является то, что это добавило бы дополнительный синтаксис к языку, и это поднимает вопрос о возвращаемых значениях (как было указано в чём-л.). Следует ли отбрасывать возвращаемое значение вызываемой функции? Должна ли вызываемая функция возвращать void или какое-либо изменение в this? Любое решение, которое я сейчас вижу, при некоторых обстоятельствах будет сбивать с толку, и что бы Си++ ни понадобилось, это больше не повод для путаницы.

2
ответ дан 18 December 2019 в 07:54
поделиться
Другие вопросы по тегам:

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