std::array has a built-in method empty() to check if the array is empty. As shown in the example copied from here:
#include <array>
#include <iostream>
int main()
{
std::array<int, 4> numbers {3, 1, 4, 1};
std::array<int, 0> no_numbers;
std::cout << std::boolalpha;
std::cout << "numbers.empty(): " << numbers.empty() << '\n';
std::cout << "no_numbers.empty(): " << no_numbers.empty() << '\n';
}
Are there any ways to check if the array is declared, with some fixed size, but not explicitly initialized?
Say, something like this?
std::array<int,4> a;
std::array<int,4> b;
a = {1,2,3,4}; //a holds some explicit values
//do not assign values to b
//how to tell the different state of a and b?
No. std::array<T, N>::empty() where N!=0 will always return false. https://en.cppreference.com/w/cpp/container/array/empty "Checks if the container has no elements, i.e. whether begin() == end()."
Similarly std::array<T, 0>::empty() will always return true, because begin() == end().
The size of a std::array object (that is, the number of elements it has) must be a compile-time constant, and cannot be changed dynamically. Thus, the empty() and size() member functions would perhaps seem somewhat redundant†(but included for reasons of compatibility with generic, container-based algorithms provided by the STL).
If you need a container with a size that can be changed, then you should use std::vector instead of std::array (although this has more run-time overheads).
The following illustrates one of the differences:
#include <iostream>
#include <array>
#include <vector>
int main()
{
std::array<int, 4> a;
std::array<int, 4> b;
a = { 1,2,3,4 }; //a holds some explicit values
std::cout << std::boolalpha;
std::cout << "a.empty(): " << a.empty() << '\n'; // false
std::cout << "b.empty(): " << b.empty() << '\n'; // false
// However ...
std::vector<int> v1;
std::vector<int> v2;
v1 = { 1,2,3,4 };
std::cout << "v1.empty(): " << v1.empty() << '\n'; // false
std::cout << "v2.empty(): " << v2.empty() << '\n'; // true
return 0;
}
†But note, those members are useful for cases when an array is passed to a function, which otherwise would not be able to determine the size (or emptiness) of its given argument(s).
I don't understand what you're asking for:
Are there any ways to check if the array is declared, with some fixed size, but not explicitly initialized?
If you have a variable of type std::array, then it has been constructed.
If it's been constructed, then the elements in the array have been constructed.
(that's done in the array constructor)
This variable std::array<std::string, 5> sa; contains 5 default-constructed strings.
So I don't know what you mean by "declared, but not explicitly initialized"
Related
I wanted a simple class which would encapsulate a pointer and a size, like C++20's std::span will be, I think. I am using C++ (g++ 11.2.1 to be precise)
I want it so I can have some constant, module-level data arrays without having to calculate the size of each one.
However my implementation 'works' only sometimes, dependent on the optimization flags and compiler (I tried on godbolt). Hence, I've made a mistake. How do I do this correctly?
Here is the implementation plus a test program which prints out the number of elements (which is always correct) and the elements (which is usually wrong)
#include <iostream>
#include <algorithm>
using std::cout;
using std::endl;
class CArray {
public:
template <size_t S>
constexpr CArray(const int (&e)[S]) : els(&e[0]), sz(S) {}
const int* begin() const { return els; }
const int* end() const { return els + sz; }
private:
const int* els;
size_t sz;
};
const CArray gbl_arr{{3,2,1}};
int main() {
CArray arr{{1,2,3}};
cout << "Global size: " << std::distance(gbl_arr.begin(), gbl_arr.end()) << endl;
for (auto i : gbl_arr) {
cout << i << endl;
}
cout << "Local size: " << std::distance(arr.begin(), arr.end()) << endl;
for (auto i : arr) {
cout << i << endl;
}
return 0;
}
Sample output:
Global size: 3
32765
0
0
Local size: 3
1
2
3
In this case the 'local' variable is correct, but the 'global' is not, should be 3,2,1.
I think the issue is your initialization is creating a temporary and then you're storing a pointer to that array after it has been destroyed.
const CArray gbl_arr{{3,2,1}};
When invoking the above constructor, the argument passed in is created just for the call itself, but gbl_arr refers to it after its life has ended. Change to this:
int gbl_arrdata[]{3,2,1};
const CArray gbl_arr{gbl_arrdaya};
And it should work, because the array it refers to now has the same lifetime scope as the object that refers to it.
I can achieve the functionality I need using option 3, however I would like to investigate whether it is possible to create the array on the stack instead.
#include <array>
#include <vector>
struct NotDefaultConstructable
{
NotDefaultConstructable(int val){};
};
int main()
{
//std::array<NotDefaultConstructable, 5> aA; // Fails to compile. [On stack]
//std::vector<NotDefaultConstructable> aV(5); // Fails to compile. [On heap]
std::vector<NotDefaultConstructable> aV; // Compiles. [ On heap]
aV.reserve(5);
}
std::array is an aggregate class type which may have a trivial, implicitly defaulted constructor. If T is not default-constructible, the implicit default constructor is defined as deleted, as per [class.ctor]/5.3.
As this applies in your case, you cannot construct an object of std::array<NotDefaultConstructable, 5> by default construction. You can, however, construct it by means of aggregate initialization:
#include <array>
struct NotDefaultConstructable {
NotDefaultConstructable(int){};
};
int main() {
std::array<NotDefaultConstructable, 3> arr{1, 2, 3};
}
In this sense, all elements of a std::array object should arguably be initialized, even if they represent a non-present object (yet to be "filled", if you will).
You could either find a an appropriate static vector container, such as boost::static_vector, or you could e.g. implement a thin wrapper around std::array which stores an array as above as well its runtime size. Another alternative would be to use a std::array of optionals:
#include <array>
#include <iostream>
#include <optional>
struct NotDefaultConstructable {
NotDefaultConstructable(int val) : val_(val) {};
int val_;
};
int main() {
std::array<std::optional<NotDefaultConstructable>, 3> arr{};
arr[1] = NotDefaultConstructable{42};
for(const auto& element : arr) {
if(element.has_value()) {
std::cout << "has value: " << element.value().val_;
} // has value: 42
}
}
where no dynamic memory allocation takes place (cppreference):
If an optional contains a value, the value is guaranteed to be allocated as part of the optional object footprint, i.e. no dynamic memory allocation ever takes place.
Judging by the fact that OP mentioned looking into using placement new, I wanted to make a full example of using a stack allocated array as memory for dynamically constructed objects.
Using this method, you can allocate stack memory without initializing it with instances. The problem, however, is that you have to monitor the object lifetime for each instance yourself. In this example, I construct all of them and can then simply assume that all of them have to be destroyed, however monitoring how many instances are alive and should be destroyed is quite messy.
This is why dfrib's answer is much more suitable in your situation, as it allows you to allocate the memory on the stack using std::array<std::optional<Type>, 5> and assign instances later. Object lifetime will also be managed for you, so is much more advisable.
Example 1: Placement New:
#include <array>
#include <iostream>
struct NotDefaultConstructable {
int Value;
NotDefaultConstructable(int val) : Value(val) {
std::cout << "constructed: " << Value << "\n";
};
~NotDefaultConstructable(){
std::cout << "destructed: " << Value << "\n";
}
};
int main() {
// allocate enough memory on the stack for 5 instances
char aV[sizeof(NotDefaultConstructable) * 5];
// get a pointer to the first NotDefaultConstructable in that array
auto avArray = static_cast<NotDefaultConstructable*>(static_cast<void*>(&aV[0]));
// use placement new to construct each instance
for (auto i = 0; i < 5; ++i)
new (&avArray[i]) NotDefaultConstructable((i + 1) * 2);
// do stuff with the instances
for (auto i = 0; i < 5; ++i)
std::cout << "instance: " << avArray[i].Value << "\n";
// destruct them all manually, this is what makes placement new a little
// cumbersome. I would advise to use std::optional instead.
for (auto i = 0; i < 5; ++i)
avArray[i].~NotDefaultConstructable();
}
example 1: https://godbolt.org/z/7jW8Pb
Example 2: std::array with std::optional
Here's an example using std::optional, which has minor overhead (about ~4 bytes per object) to achieve much more convenience:
#include <array>
#include <optional>
#include <iostream>
struct NotDefaultConstructable {
int Value;
NotDefaultConstructable(int val) : Value(val) {
std::cout << "constructed: " << Value << "\n";
};
~NotDefaultConstructable(){
std::cout << "destructed: " << Value << "\n";
}
};
int main() {
// allocate enough memory on the stack for 5 instances
std::array<std::optional<NotDefaultConstructable>, 5> avArray;
// use placement new to construct each instance
for (auto i = 0; i < 5; ++i)
avArray[i] = NotDefaultConstructable((i + 1) * 2);
// do stuff with the instances
for (auto i = 0; i < 5; ++i)
std::cout << "instance: " << avArray[i].value().Value << "\n";
}
example 2: https://godbolt.org/z/Ynx8aE
You can try the following
#include <iostream>
struct NotDefaultConstructable {
NotDefaultConstructable(int val) {
};
};
int main() {
NotDefaultConstructable aV[5] { 6, 6, 6, 6, 6 };
}
In the docs on std::span constructors, there isn't one that accepts an std::vector.
Then, how come this code (source page) compiles?
// createSpan.cpp
#include <algorithm>
#include <iostream>
#include <span>
#include <vector>
int main() {
std::cout << std::endl;
std::cout << std::boolalpha;
std::vector myVec{1, 2, 3, 4, 5};
std::span mySpan1{myVec}; // (1)
std::span mySpan2{myVec.data(), myVec.size()}; // (2)
bool spansEqual = std::equal(mySpan1.begin(), mySpan1.end(),
mySpan2.begin(), mySpan2.end());
std::cout << "mySpan1 == mySpan2: " << spansEqual << std::endl; // (3)
std::cout << std::endl;
}
i.e. which constructor of std::span was invoked at (1)?
It's the constructor (7) in the overload set:
template< class R >
explicit(extent != std::dynamic_extent)
constexpr span( R&& r );
From the explanation:
Constructs a span that is a view over the range r; the resulting span has size() == std::ranges::size(r) and data() == std::ranges::data(r).
There are further restriction on when this signature takes part in overload resolution, but that's the essence. And std::vector satisfies these requirements.
It's a good thing that this is kept only as constrained as necessary, because it allows custom (non-std) containers to allow for implicit conversion to std::span instances.
Here is a minimal example where an object of type WrapMap contains an unordered_map. The only thing that will change in the map is the values, not the length and not the keys.
However, I have found that each value passed into each pair is copied twice.
By using move, it seems to have reduced the number of copies by 1 (although the move doesn't show up in the output, so maybe I've done something wrong).
#include <iostream>
#include <unordered_map>
using std::cout;
struct MyStruct {
int x;
MyStruct(int x) : x(x) { cout << "Constructed " << this << " from " << x << "\n"; }
MyStruct(const MyStruct& from) : x(from.x) { cout << "Copied " << this << " from " << &from << "\n"; }
MyStruct(MyStruct&& from) : x(from.x) { cout << "Moved " << this << " from " << &from << "\n"; }
~MyStruct() { cout << "Destructed " << this << " from " << x << "\n"; }
};
struct WrapMap {
std::unordered_map<std::string, MyStruct>&& my_map;
WrapMap(std::unordered_map<std::string, MyStruct>&& kv)
: my_map(std::move(kv)) {
/*
// Just to make sure it inputs the values correctly
cout << "{";
for (auto it = my_map.begin(); it != my_map.end(); ++it) {
if (it != my_map.begin()) cout << ", ";
cout << it->first << ": MyStruct " << it->second.x;
}
cout << "}\n";
*/
}
};
int main() {
WrapMap object({
{"foo", 2},
// several pairs
});
}
Constructed 0x7ffd76fadbb8 from 2
Copied 0x2611c80 from 0x7ffd76fadbb8
{foo: MyStruct 2}
Destructed 0x7ffd76fadbb8 from 2
Destructed 0x2611c80 from 2
My assumption is that the long pointer points to const memory (just a guess) and so it has to copy each element from const memory to non-const memory.
I have attempted to use an initializer_list<pair<string, MyStruct>> but I couldn't convert it to an unordered_map.
std::unordered_map<std::string, MyStruct> object = { {"foo", 2} } calls the copy constructor for each value, it seems.
How can I make it so that each key is never copied (or at least minimise it?)
Related: Insert in unordered map calls constructor
emplace
You can use the emplace member function of unordered_map:
Inserts a new element into the container constructed in-place with the given args if there is no element with the key in the container.
Careful use of emplace allows the new element to be constructed while avoiding unnecessary copy or move operations. The constructor of the new element (i.e. std::pair<const Key, T>) is called with exactly the same arguments as supplied to emplace, forwarded via std::forward<Args>(args).... [...]
std::unordered_map<std::string, MyStruct> m;
m.emplace(std::make_pair("foo", 2));
C++17: try_emplace
As of C++17, you can also make use of try_emplace which allows retaining a given resource passed to it if the key already exists:
[...] Unlike insert or emplace, these functions do not move from rvalue arguments if the insertion does not happen, which makes it easy to manipulate maps whose values are move-only types, such as std::unordered_map<std::string, std::unique_ptr<foo>>. In addition, try_emplace treats the key and the arguments to the mapped_type separately, unlike emplace, which requires the arguments to construct a value_type (that is, a std::pair) [...].
std::unordered_map<std::string, MyStruct> m;
m.try_emplace("foo", 2);
Minimal working example:
#include <tuple>
struct example
{
example(int, char) {}
};
int main()
{
std::tuple<example, int, double>
my_tuple(example(0, 'x'), 42, .0);
// std::tuple t = make_my_tuple(0, 'x');
return 0;
}
This works.
Is there a more elegant way to initialize only the first member, like I sketched in the comment? One which only takes the arguments to construct the first tuple member and does not initialize the others?
The reason I ask? I am just interested in the semantics of the language.
You say that giving values for the other two members is not necessary - are you worried about performance? Or that there may be no suitable value for these members?
If it's the latter, you could have your tuple hold boost::optionals. e.g.
#include <tuple>
#include <boost/optional.hpp>
using namespace boost;
struct example
{
example(int, char) {}
};
typedef std::tuple<example, optional<int>, optional<double>> MyTuple;
int main()
{
MyTuple my_tuple(example(0, 'x'), optional<int>(), optional<double>());
return 0;
}
You now semantically have the int and float "uninitialised", and can query their value as such.
To make this more elegant, you can wrap this into a function, using the perfect forwarding idiom for the arguments (in general; in this case your arguments are cheap to copy, so no speed benefit from doing this):
template <class... Args>
MyTuple make_mytuple(Args&&... args)
{
return MyTuple(example(std::forward<Args>(args)...), optional<int>(), optional<double));
}
The advantage of this template is that it's resilient to changes in example's constructor. If you add another argument, just call make_mytuple with the new arguments and it will work.
Your other point about the copying in the tuple construction is valid, but in reality I believe this will be optimal on most compilers. (a combination of RVO and elision of copies when passing an rvalue to a function by value).
You can use uniform initialization. Sadly, you cannot define a default value, argument will be initialized with the default constructor or 0.
#include <iostream>
#include <tuple>
enum class Result {Full, Partial, Empty};
std::tuple<bool, int, double> get_tuple(Result type)
{
if (type == Result::Full)
return {true, 42, 3.14159};
else if (type == Result::Partial)
return {true, 42, {}};
else
return {};
}
int main()
{
bool b;
int i;
double d;
std::tie(b, i, d) = get_tuple(Result::Full);
std::cout << b << " " << i << " " << d << std::endl;
std::tie(b, i, d) = get_tuple(Result::Partial);
std::cout << b << " " << i << " " << d << std::endl;
std::tie(b, i, d) = get_tuple(Result::Empty);
std::cout << b << " " << i << " " << d << std::endl;
return 0;
}
output:
1 42 3.14159
1 42 0
0 0 0