Я задаюсь вопросом, почему C++ (и возможно другие языки, я не уверен), не позволяет операторы как это.
MyObject foo.DoBar();
Вы думали бы, что язык мог понять для построения объекта, затем вызвать функцию. Единственная причина я могу думать об этом не работа, состоит в том, что, если бы конструкция объекта перестала работать, оператор все еще попытался бы вызвать функцию.
Каковы причины, почему те, кто помогает разработать и интегрировать новые возможности в C++ (и возможно другие языки) не позволяют это?
Невозможно выполнить !
операция на @ head
, если она не существует. Сначала необходимо инициализировать его. Вероятно, следует объявить его нулевым
.
В дополнение к предложению Матчу, вы также можете использовать defined?
для инициализации @ head
без предупреждения:
if defined? @head
...
else
@head = new_node
end
Нормальный идиом для такого рода вещей является
@head ||= new_node
, который также не вызовет предупреждения, но в этом случае кажется, что вам нужно сделать что-то, если @ head
не был определен, и это не idempotent так что | | =
не идти на работу очень хорошо в данном случае. | | =
также имеет недостаток, заключающийся в том, что быть не удается различить ложные, нулевые или неустановленные значения. Инициализация до nil
в инициализации, вероятно, является лучшим выбором.
Вы можете построить объект и немедленно вызвать функцию для него, вы просто не можете назначить объект переменной, если вы делаете это:
MyObject().DoBar();
Практическая причина этого ограничения заключается в том, что конструктор создает объект, и вызываемая функция может также иметь возвращаемое значение, так что в итоге будут получены два значения, созданные одним и тем же оператором. Тогда вам понадобится какой-то специальный синтаксис, чтобы назначить оба этих значения переменным, чего больше нигде не происходит.
И небольшое удобство, которое может быть достигнуто путем прямого вызова метода, не является большим преимуществом, что стоило бы ввести новый синтаксис для него.
Вместо 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
Я думаю, что вам нужен конкретный пример, чтобы действительно сделать дело.
Ну вот проблема: что если foo
необходимо использовать конструктор не по умолчанию. Теперь это
MyObject foo(arg1, arg2).DoBar();
Это такое грязное и действительно не намного лучше, чем
MyObject foo(arg1, arg2);
foo.DoBar();
, помните: код должен быть легко понятен!
Обратите внимание, что это вроде возможно делать то, что вы хотите, если Dobar возвращает ссылку на *
:
MyObject foo = MyObject().DoBar();
с C ++ 0x Перемещение конструкторов, это повлечет за собой немного накладных, но пока Тогда ожидайте ложную копию.
В последнем параграфе вы ссылаетесь на комитет по стандартам C++. Он был очень занят, и важные особенности языка действительно отбрасываются, потому что у комитета заканчивается время (например, std::unorddered_map
в текущем стандарте и концепциях в предстоящем). Они не заинтересованы в том, чтобы вносить незначительные изменения без веских на то оснований. В дни, предшествующие заседанию комитета по стандартам, Bjarne Stroustrup не был заинтересован в добавлении незначительных функций только ради них.
C не было этого объявления, возможно, потому что никто не хотел этого (тогда мало кто объявлял типы с ассоциированными функциями), возможно, потому что это могло сбить с толку. Множество особенностей компьютерных языков существуют в исторических целях и могут указывать на то, что кто-то сделал случайный выбор десятилетия назад. Это не значит, что изменять их без веской причины, как только они будут установлены.
Правильный вопрос не в том, "почему бы им не сделать это изменение?", а в том, "почему бы им не сделать это изменение?". Предложенное вами изменение не выглядит действительно полезным, так как я могу сделать то же самое с двумя строками кода; полный дополнительный набор текста - одна точка с запятой, один конец строки и повторение имени переменной.
Недостатком является то, что это добавило бы дополнительный синтаксис к языку, и это поднимает вопрос о возвращаемых значениях (как было указано в чём-л.). Следует ли отбрасывать возвращаемое значение вызываемой функции? Должна ли вызываемая функция возвращать void
или какое-либо изменение в this
? Любое решение, которое я сейчас вижу, при некоторых обстоятельствах будет сбивать с толку, и что бы Си++ ни понадобилось, это больше не повод для путаницы.