I have a class T, it looks like this:
class T {
uint64_t id;
std::string description;
char status;
uint64_t createdAt;
uint64_t updatedAt;
T(uint64_t c_id, std::string_view c_description, char c_status, uint64_t c_createdAt, uint64_t c_updatedAt) :
id(c_id),
description(c_description),
status(c_status),
createdAt(c_createdAt),
updatedAt(c_updatedAt) {}
T(T&& other) :
id(other.id),
description(std::move(other.description)),
status(other.status),
createdAt(other.createdAt),
updatedAt(other.updatedAt) {}
// member functions
};
At some point, I need to append an optional into a vector. What is the best way between these options (or are there other options)?
std::optional<T> opt = myFunction();
std::vector<T> tasks;
if(opt.has_value()) {
tasks.push_back(*opt);
tasks.push_back(opt.value());
tasks.push_back(std::move(*opt));
tasks.emplace_back(*opt);
tasks.emplace_back(opt.value());
tasks.emplace_back(std::move(*opt));
}
I have a class T, it looks like this:
class T {
uint64_t id;
std::string description;
char status;
uint64_t createdAt;
uint64_t updatedAt;
T(uint64_t c_id, std::string_view c_description, char c_status, uint64_t c_createdAt, uint64_t c_updatedAt) :
id(c_id),
description(c_description),
status(c_status),
createdAt(c_createdAt),
updatedAt(c_updatedAt) {}
T(T&& other) :
id(other.id),
description(std::move(other.description)),
status(other.status),
createdAt(other.createdAt),
updatedAt(other.updatedAt) {}
// member functions
};
At some point, I need to append an optional into a vector. What is the best way between these options (or are there other options)?
std::optional<T> opt = myFunction();
std::vector<T> tasks;
if(opt.has_value()) {
tasks.push_back(*opt);
tasks.push_back(opt.value());
tasks.push_back(std::move(*opt));
tasks.emplace_back(*opt);
tasks.emplace_back(opt.value());
tasks.emplace_back(std::move(*opt));
}
Share
Improve this question
edited Mar 25 at 10:05
bramar2
asked Mar 25 at 9:13
bramar2bramar2
771 silver badge4 bronze badges
4
|
3 Answers
Reset to default 8// copies optional content into vector, optional unchanged
// undefined behavior if optional was originally empty
tasks.push_back(*opt);
// copies optional content into vector, optional unchanged
// throws std::bad_optional_access if optional is empty
tasks.push_back(opt.value());
// moves the optional content into vector, opt std::string member is now empty
// undefined behavior if optional was originally empty
tasks.push_back(std::move(*opt));
// moves the optional content into vector, opt std::string member is now empty
// throws std::bad_optional_access if optional is empty
tasks.push_back(std::move(opt.value()));
the cheapest (generating the least amount of assembly instructions) would be
if (opt) // get rid of UB in operator*
{
tasks.push_back(std::move(*opt)); // move the contents of opt into tasks
}
// bonus: same syntax as a pointer!
there is no difference between push_back
and emplace_back
in this context. emplace_back
is only useful when the type of the argument is different than the type of the container and you want to have a conversion. push_back
will do a conversion then a move, whereas emplace_back
will just do a conversion. Don't abuse emplace_back
as it does explicit
conversions implicitly.
In C++26, the simplest way to copy-insert the contents of opt
is
std::optional<T> opt = myFunction();
std::vector<T> tasks;
tasks.append_range(opt);
And the simplest way to move-insert the contents of opt
is
std::optional<T> opt = myFunction();
std::vector<T> tasks;
tasks.append_range(opt | std::views::as_rvalue);
Depending on your need, it might also be simpler to just hold a list of optionals
std::optional<T> opt = myFunction();
std::vector<std::optional<T>> maybeTasks;
maybeTasks.push_back(opt);
and worry later about wether they exist, or if all tasks are created and then handled separately:
std::vector<T> taskList;
for (auto it : maybeTasks) {
if(it.has_value()) {
taskList.push_back(it.value());
}
}
T
have a move constructor? You left out all member functions, including the most important one for this question. – MSalters Commented Mar 25 at 9:17T
symbol name is usually used as template parameter. So when you use this as actual class name this is vary confusing for may developers. You should useFoo
orBar
. – Marek R Commented Mar 25 at 11:38