Страницы

Поиск по вопросам

воскресенье, 5 января 2020 г.

Порядок конструирования аргументов функции

#cpp


Встретил статью «Пять подводных камней при использовании shared_ptr»,
в которой утверждается, что:


  в строке кода:

foo( shared_ptr(new Widget), bar() );

  
  порядок конструирования не определен.
  Все зависит от конкретного компилятора
  и флагов компиляции. Например, это
  может произойти так:
  
  
  new Widget 
  вызов функции bar 
  конструирование shared_ptr
  вызов функции foo
  


Почему так? Я считал, что в списке параметров функции точки следования определены
запятыми и аргументы (границы между которыми очерчивают запятые) действительно могут
быть обработаны в любом порядке, НО каждый отдельный аргумент, если уж начал обрабатываться
программой, то обрабатывается до конца. А т.к. shared_ptr(new Widget) - это
отдельный аргумент, то он обработается целиком (т.е. в приведённом списке пункты 1
и 3 всегда будут идти подряд).

Разве не так? Ткните, пожалуйста, меня носом в "что бы прочесть", чтобы уяснить свою
ошибку.
Спасибо.

Обновление

@KoVadim, в статье рассматривается случай, когда выполнение bar() бросает исключение.
Тогда (исходя из предложенного порядка обработки аргументов) получается, что объект
Widget сконструирован, но shared_ptr ещё нет (следовательно и не завладел объектом
Widget). Отсюда утечка памяти.

Обновление 2

@KoVadim, да, действительно, Вы правы. Дело именно в этом. Прочёл дальше комментарии
к статье - там кто-то уже задал подобный вопрос. В ответ ему посоветовали ссылку http://www.gotw.ca/gotw/056.htm
Тут разбирается подобный случай. А причина неопределённости, как Вы уже заметили, в
том, что запятая, отделяющая параметры функции друг от друга - это разделитель (comma
separator), а не оператор запятая (comma operator). А точкой следования из них является
только оператор.
Спасибо за пинок в правильном направлении.
    


Ответы

Ответ 1



В статье на хабре написано все верно. Вот выдержка из cpp reference: “Sequenced-before” is an asymmetric, transitive, pair-wise relationship between evaluations within the same thread (it may extend across threads if atomic types and memory barriers are involved). If a sequence point is present between the subexpressions E1 and E2, then both value computation and side effects of E1 are sequenced before every value computation and side effect of E2 If evaluation A is sequenced before evaluation B, then evaluation of A will be complete before evaluation of B begins. (since C11) If A is not sequenced before B and B is sequenced before A, then evaluation of B will be complete before evaluation of A begins. (since C11) If A is not sequenced before B and B is not sequenced before A, then two possibilities exist: (since C11) evaluations of A and B are unsequenced: they may be performed in any order and may overlap (within a single thread of execution, the compiler may interleave the CPU instructions that comprise A and B) evaluations of A and B are indeterminably-sequenced: they may be performed in any order but may not overlap: either A will be complete before B, or B will be complete before A. The order may be the opposite the next time the same expression is evaluated. Как видите, в случае, если порядок А и Б не определен, возможны два варианта: с оверлапом и без него. Собственно, написанная Вами выше последовательность, когда bar() вызывается между new и вызовом конструктора, является первым случаем, вполне возможным согласно стандарту. Место, о котором я говорю: evaluations of A and B are unsequenced: they may be performed in any order and may overlap (within a single thread of execution, the compiler may interleave the CPU instructions that comprise A and B)

Ответ 2



Запятые, разделяющие аргументы функции, и оператор запятая - это разные вещи. По поводу порядка вычисления. А какая разница? Проблемы будут только в том случае, если конструктор shared_ptr зависит от bar() (глобальными переменными), но это уже страх и ужас.

Считывание строки из файла и дальнейшая работа со следующей по счету строкой

#cpp #алгоритм


Название, может, криво написал, лучше опишу задание. 
Написать программу, которая в качестве аргумента командной строки принимает имя текстового
файла, содержащего элементы трёх видов:
+ <слово>
- <слово>
? <слово>

Элементы отделяются друг от друга одним или несколькими разделителями – пробелами,
табуляциями, символами новой строки. Слово с предшествующим плюсом добавляется в упорядоченный
динамический список, если его там ещё нет (в качестве функции сравнения слов использовать
лексикографическое сравнение). Если числу предшествует минус, то это слово удаляется
из списка (если оно было в нём). Если перед словом стоит вопрос, то оно печатается
в выходной поток в отдельной строке вместе со словом Yes или No в зависимости от того,
присутствует ли это слово в построенном на тот момент списке.
В общем, что мне удалось сделать.
#include 
#include 
#include 
#include 
#include 

class Node  
{
public:
char* data;
Node *next;

Node()
{
    char* data = new char[30];
}

Node(char* element)
{
    strcpy_s(data, 20, element);
    next = NULL;
}

char *getdata()
{
    return data;
}
};

class DynList
{
Node *head;
public:

DynList()
{
    head = NULL;
}

~DynList()
{
    Node *temp;
    while (head != NULL)
    {
        head = head->next;
        delete temp;
        temp = head;
    }
}

void AddFirst(DynList &l, char* element);
Node* Search(DynList &l, char* element);
void Delete(DynList &l, Node *temp);
};

void DynList::AddFirst(DynList &l, char* element)
{

Node *NewNode = new Node;
NewNode->data = element;
NewNode->next = NULL;

NewNode->next = l.head;
l.head = NewNode;
}

Node* DynList::Search(DynList &l, char* element)
{
while (head != NULL)
{
    if (head->data = element)
        return l.head;
    l.head = l.head->next;
}
return l.head;
}

void DynList::Delete(DynList &l, Node *temp)
{
if (temp == l.head)
{
    l.head = temp->next;
}

//рабоча¤ переменна¤-узел дл¤ движени¤ по списку
Node *r = new Node;
r = head;
while (r->next != temp)
{
    r = r->next;
}
r->next = temp->next;
delete(temp);
}

int main()
{
char* element = new char[30];
DynList vars;
std::ifstream file("3.txt");

if (file.is_open() )
{
    while (!file.eof() )
    {
        getline(file, element);
    }

}

return 0;
}

Во-первых, компилятор (работаю в VS) ругается на getline. Можете помочь? Текстовые
данные у меня хранятся в таком виде: 
 + The + donation + will + go + toward + the ? CDC - Global + Disaster + Response

Я хочу применить такой алгоритм: 

Считываю слова из файла.  

Далее прописываю условия, что если считывается один из символов-флагов ("+", "-",
"?"), то к следующему слову применяется соответствующая функция-метод класса. 

Так вот, как мне обратиться к следующему после флага слову?    


Ответы

Ответ 1



Или на Питоне: #!/usr/bin/env python3 import fileinput words = set() #NOTE: it is unordered but it doesn't affect the result tokens = (token for line in fileinput.input() for token in line.split()) for op, word in zip(*[tokens]*2): if op == '+': words.add(word) elif op == '-': words.discard(word) elif op == '?': print(word, "Yes" if word in words else "No") @VladD спросил: А как функционирует *[tokens]*2 zip(*[iterator]*n) -- это (довольно непрозрачная, что необычно) идиома по обходу итератора n элементов за раз. В официальной документации это itertools' grouper рецепт. Смотри What is the most “pythonic” way to iterate over a list in chunks? и Что значит * (звёздочка) и ** двойная звёздочка в Питоне? Основная идея в том, что zip() на каждом шаге вызывает next() функцию n раз на одном и том же итераторе: >>> from itertools import zip_longest >>> for a, b, c in zip_longest(*[iter(range(10))]*3, fillvalue='default'): ... print(a, b, c) ... 0 1 2 3 4 5 6 7 8 9 default default zip_longest() необходим только если кол-во элементов в итераторе не кратно n. Итератор это простой объект, который генерирует элементы, если next() вызыван: >>> it = iter(range(2)) >>> next(it) 0 >>> next(it) 1 >>> next(it) Traceback (most recent call last): File "", line 1, in StopIteration >>> next(it) Traceback (most recent call last): File "", line 1, in StopIteration Итератор можно пройти только один раз. Чтобы перезапустить обход, необходимо создать новый итератор. (x*x for x in iterable) выражение возвращает итератор.

Ответ 2



Доброго времени суток! Вот код, который решает Вашу задачу: #include #include #include #include #include #include #define _DEBUG_OPS enum operation { op_unknown = 0, op_push = 1, op_pop = 2, op_show = 3 }; inline std::istream& operator>> (std::istream& stream, operation& op) { std::string s; stream >> s; if (s == "+") { op = op_push; return stream; } if (s == "-") { op = op_pop; return stream; } if (s == "?") { op = op_show; return stream; } op = op_unknown; return stream; } typedef std::pair op_node; typedef std::set string_set; void execute_op(const op_node& n, string_set& s) { using std::cout; using std::endl; std::string str = n.second; string_set::const_iterator it = s.find(str); switch(n.first) { case op_push: #ifdef _DEBUG_OPS cout << "PUSH " << str << endl; #endif s.insert(str); break; case op_pop: #ifdef _DEBUG_OPS cout << "POP " << str << endl; #endif if (it != s.end()) { s.erase(it); } break; case op_show: #ifdef _DEBUG_OPS cout << "SHOW "; #endif cout << str << " " << (it != s.end() ? "YES" : "NO") << endl; break; case op_unknown: default: cout << "error: unknnown operation..." << endl; exit(1); } } int main() { using namespace std; string_set strings; op_node item; ifstream input("input.txt"); if (!input) { cout << "error: unable to read input..." << endl; return 1; } string s; while(input) { input >> item.first; input >> item.second; if (!input) { // End-Of-Stream cout << "EOS" << endl; break; } execute_op(item, strings); } // print out all strings in string set #ifdef _DEBUG_OPS copy(strings.begin(), strings.end(), ostream_iterator(cout << endl, "\n")); #endif return 0; } Алгоритм следующий: Читаем из входного потока оператор. Читаем из входного потока строку. Выполняем действие над строкой в соответствии с оператором. Повторяем действия с 1-3, пока не конец потока. Файл input.txt в моем случае имел такой вид: + The + donation + will + go + toward + the ? CDC - Global + Disaster + Response - The ? The ? will На выходе получился такой результат: PUSH The PUSH donation PUSH will PUSH go PUSH toward PUSH the SHOW CDC NO POP Global PUSH Disaster PUSH Response POP The SHOW The NO SHOW will YES EOS Disaster Response donation go the toward will Здесь для наглядности напечатано действие, производимое со строкой, а в конце напечатан весь получившийся список слов. Чтобы отключить вывод на печать этой отладочной информации, закомментируйте: #define _DEBUG_OPS Надеюсь, я правильно понял, что Вы хотели сделать, и Вам помог! Если есть вопросы по коду, пишите в комментариях, хотя, на мой взгляд, все очевидно. ) Успехов!

Ответ 3



В качестве упорядоченного динамического контейнера можно использовать std::set, порекомендованный @VladD в комментарии к вопросу. skipws флаг (установлен по умолчанию) позволяет удобно считывать поля, разделённые пробелом, c помощью operator>> (что такое пробел, может зависеть от локали, связанной с потоком): #include #include #include #include int main(int argc, char* argv[]) { using namespace std; if (argc != 2) { cerr << "Usage: " << (argc > 0 ? argv[0] : "set-words") << " FILE\n"; return 2; } set words; // ordered set ifstream file(argv[argc-1]); for (string op, word; file >> op >> word; ) { if (op == "+") words.insert(word); else if (op == "-") words.erase(word); else if (op == "?") cout << word << " " << (words.count(word) ? "Yes": "No") << endl; else { cerr << "error: unexpected operator, got '" << op << "'\n"; return 1; } } return !file.eof(); } Код достаточно краток и прямолинеен. Можно добавить ещё сообщения об ошибках, чтобы отличить ошибки ввода/вывода, например, ошибку открытия файла от ошибки чтения из файла.

Ответ 4



Вот полное решение на C#, для сравнения: var pairs = File.ReadLines(f) .SelectMany(s => s.Split(null, StringSplitOptions.RemoveEmptyEntries)) .Batch(2, strings => new { op = string.First(), arg = strings.Last() }); var curr = new HashSet(); foreach (var pair in pairs) switch (pair.op) { case "+": curr.Add(pair.arg); break; case "-": curr.Remove(pair.arg); break; case "?": Console.WriteLine(pair.arg + ": " + curr.Contains(pair.arg) ? "Yes" : "No"); break; }

Посоветуйте научно-популярные книги по computer science [закрыт]

#алгоритм #книги


        
             
                
                    
                        
                            Закрыт. Этот вопрос не по теме. Ответы на него в данный
момент не принимаются.
                            
                        
                    
                
                            
                                
                
                        
                            
                        
                    
                        
                            Хотите улучшить этот вопрос? Переформулируйте вопрос,
чтобы он соответствовал тематике «Stack Overflow на русском».
                        
                        Закрыт 4 года назад.
                                                                                
           
                
        
Разумеется, вы знаете книги, которые простым языком объясняют, как всё устроено в
определённой области науки, разбирают интересные примеры и вкратце суммируют, почему
она нужна и полезна. Про разные разделы физики и математики таких книг полным полно.
Однако, я с удивлением не нагуглил ничего интересного на тему компьютеров и алгоритмов.
Конечно, есть "Энциклопедия профессора Фортрана" и "Я был в компьютерном городе", но
они совсем для младших классов да и устарели.
Быть может, кто-нибудь подскажет книги такого толка? Интересуют как книги, которые
можно дать почитать школьнику для подстёгивания интереса к предмету, так и томики для
уже более-менее сформировавшихся специалистов.
UPD Спрашиваю именно про научно-популярные издания, а не учебники. Как, например
"Гёдель, Эшер, Бах" Хофстедера или "Занимательная физика" Перельмана    


Ответы

Ответ 1



Не совсем уж научпоп, но возможно понравится, написана хорошо. Код. Тайный язык информатики

Ответ 2



Альфред Реньи. "Записки студента по теории информации"

Ответ 3



Дж. Маккормик. Девять алгоритмов, которые изменили будущее Дж. Глик. Информация. История. Теория. Поток

Ответ 4



http://computersbooks.net/ неплохой сайт с кучей инфы по сабжу!

Будильник на JAVA

#android #java


Я начинающий в JAVA. До этого писал на Delphi. Если у кого-то есть пример кода на
Яве, буду признателен. Но самое главное, как запустить ВИБРАЦИЮ при срабатывании будильника.
Это, наверное, самое главное, что нужно.    


Ответы

Ответ 1



Вы, наверное, начали программировать для мобильных устройств? А именно Android? Я не знаю, может, у Вас в компьютере есть виброзвонок. Если Вы имели в виду для Андроид, тогда следует получить объект типа Vibrator с помощью системеного сервиса. import android.os.Vibrator; // Импорт для класса Vibrator Vibrator v = (Vibrator) this.context.getSystemService(Context.VIBRATOR_SERVICE); // Получение объекта с помощью системного сервиса v.vibrate(1000); // Вибрация 1 секунду. И не забудьте прописать разрешения (запрос на разрешение) в файле AndroidManifest.xml

Как получить список аудиозаписей с помощью VK SDK на Android?

#android #java #vkontakte_api


Сабж. Вместе с VK SDK поставлялся тестовый проект. В нём на примерах пытался получить
список аудиозаписей. Укажите на ошибки, что я делаю не так?
P.S. Авторизовался. В скоупы определил доступ к аудиозаписям.
VKRequest requestaudio = new VKRequest("audio.get",     VKParameters.from(VKApiConst.OWNER_ID,
"1", VKApiConst.COUNT, "3"));
                requestaudio.executeWithListener(new VKRequestListener() {
                    @Override
                    public void onComplete(VKResponse response) {
                        super.onComplete(response);
                    }
                    @Override
                    public void onError(VKError error) {
                        super.onError(error);
                    }
                });
    


Ответы

Ответ 1



А где запускаешь этот код? Я запустил в Activity в onCreate. все работает. VKParameters params = new VKParameters(); params.put(VKApiConst.OWNER_ID, "1"); params.put(VKApiConst.COUNT, "3"); requestaudio= new VKRequest("audio.get",params); requestaudio.executeWithListener(new VKRequest.VKRequestListener() { @Override public void onComplete(VKResponse response) { super.onComplete(response); } @Override public void onError(VKError error) { super.onError(error); } });

Ответ 2



Вот код, который позволяет получить свои аудиозаписи начиная с "m_nOffset" и заканчивая "m_nOffset+m_nCount". В результате с помощью Vk SDK преобразуем response в VKList, а сним работаем как с обычным листом и получаем все нужные нам даные. VKParameters params = new VKParameters(); params.put(VKApiConst.OFFSET, m_nOffset); params.put(VKApiConst.COUNT, m_nCount); VKRequest requestAudio = VKApi.audio().get(params); requestAudio.executeWithListener(new VKRequest.VKRequestListener() { @Override public void onComplete(VKResponse response) { super.onComplete(response); for(int i = 0;i<((VKList)response.parsedModel).size();i++){ VKApiAudio vkApiAudio = ((VKList)response.parsedModel).get(i); AudioFileData audioFileData = new AudioFileData(); audioFileData.setArtist(vkApiAudio.artist); audioFileData.setTitle(vkApiAudio.title); audioFileData.setDuration(vkApiAudio.duration); audioFileData.setId(vkApiAudio.id); audioFileData.setIdLyrics(vkApiAudio.lyrics_id); audioFileData.setUrl(vkApiAudio.url); audioFileDataArrayList.add(audioFileData); } mAudioRecyclerViewAdapter = new AudioRecyclerViewAdapter(audioFileDataArrayList,m_tvPlayingTitle); mRecyclerView.setAdapter(mAudioRecyclerViewAdapter); mAudioRecyclerViewAdapter.notifyDataSetChanged(); } @Override public void attemptFailed(VKRequest request, int attemptNumber, int totalAttempts) { super.attemptFailed(request, attemptNumber, totalAttempts); } @Override public void onError(VKError error) { super.onError(error); } @Override public void onProgress(VKRequest.VKProgressType progressType, long bytesLoaded, long bytesTotal) { super.onProgress(progressType, bytesLoaded, bytesTotal); } });

Как лучше исправить foreach цикл, внутри которого расширяется перебираемая коллекция?

#c_sharp #foreach


Коллекция выглядит так:
public class myList : List { }

Мне нужно повторять цикл до тех пор, пока он добавляет новые элементы:
do {
    newObjectAdded = false;
    foreach (myClass obj in myList) {
        //...
        if (some_condition) {
            myList.Add(newObj); 
            newObjectAdded = true;}
        //...
    }
} while (newObjectAdded);

После того, как в лист добавится элемент, в строке foreach (myClass obj in myList)
я получаю ошибку - коллекция была изменена, невозможно выполнить операцию перечисления.
Можно заменить foreach на цикл с итератором, но от этого обращение к объектам станет
довольно громоздким. Ещё есть вариант с заменой списка на LinkedList, но это ещё хуже,
в данном случае.
Существует ли какой-то более элегантный способ?    


Ответы

Ответ 1



Сам разобрался. Достаточно написать: foreach (myClass obj in myList.ToArray()) {

Как сделать висящее в трее приложение?

#android #java


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


Ответы

Ответ 1



http://habrahabr.ru/post/140928/

Ответ 2



Вообще-то эта штука называется Notification. Достаточно внятно об этом можно прочитать здесь или тут. Если совсем кратко, то это в общем некая компонента приложения независимая от жизненного цикла Activity обладающая собственными вьюшками (RemoteView) и позволяющая запускать подобия интентов (PendingIntent).