C++11 introduced the possibility of delegating construction from one constructor to another - "delegating constructors".
But - when doing that, can we use the this pointer? e.g. as an argument to one of the constructors we're delegating to? It's not trivial to assume that we can while the "real constructor" has not actually been invoked yet.
For a definitive answer one would need to read the standard (and even there it might not be entirely clear, see #BenjaminBanner's comment). But in practice - yes, apparently we can use this in constructor delegation.
The following example:
#include <iostream>
struct A {
A(int x_, void* p_) : x(x_), p(p_) { }
A(void* p_) : A(0, p_) { }
A() : A(this) { }
int x;
void* p;
};
int main() {
A a;
std::cout << "&a == " << &a << "\n";
std::cout << "a.p == " << a.p << "\n";
}
compiles (GodBolt) with all of GCC, clang and MSVC. They do not warn about doing this, even with -Wall -Wpedantic -Wextra or /W4 for MSVC.
It also runs (coliru.com) and produces the expected output (at the link you have the g++-compiled version, clang++ can be checked there as well).
Related
I've got the following test.cpp file
#include <string>
#include <functional>
#include <unordered_map>
#include <iostream>
class Mystuff {
public:
std::string key1;
int key2;
public:
Mystuff(std::string _key1, int _key2)
: key1(_key1)
, key2(_key2)
{}
};
namespace std {
template<>
struct hash<Mystuff *> {
size_t operator()(Mystuff * const& any) const {
size_t hashres = std::hash<std::string>()(any->key1);
hashres ^= std::hash<int>()(any->key2);
std::cout << "Hash for find/insert is [" << hashres << "]" << std::endl;
return (hashres);
}
};
}; /* eof namespace std */
typedef std::unordered_map<Mystuff *, Mystuff *>mystuff_map_t;
mystuff_map_t map;
int insert_if_not_there(Mystuff * stuff) {
std::cout << "Trying insert for " << stuff->key1 << std::endl;
if (map.find(stuff) != map.end()) {
std::cout << "It's there already..." << std::endl;
return (-1);
} else {
map[stuff] = stuff;
std::cout << "Worked..." << std::endl;
}
return (0);
}
int main(){
Mystuff first("first", 1);
Mystuff second("second", 2);
Mystuff third("third", 3);
Mystuff third_duplicate("third", 3);
insert_if_not_there(&first);
insert_if_not_there(&second);
insert_if_not_there(&third);
insert_if_not_there(&third_duplicate);
}
You can compile with g++ -o test test.cpp -std=gnu++11.
I don't get what I'm doing wrong with it: the hash keying algorithm is definitely working, but for some reason (which is obviously in the - bad - way I'm doing something), third_duplicate is inserted as well in the map, while I'd wish it wasn't.
What am I doing wrong?
IIRC unordered containers need operator== as well as std::hash. Without it, I'd expect a compilation error. Except that your key is actually MyStuff* - the pointer, not the value.
That means you get the duplicate key stored as a separate item because it's actually not, to unordered_map, a real duplicate - it has a different address, and address equality is how unordered_map is judging equality.
Simple solution - use std::unordered_map<Mystuff,Mystuff> instead. You will need to overload operator== (or there's IIRC some alternative template, similar to std::hash, that you can specialize). You'll also need to change your std::hash to also accept the value rather than the pointer.
Don't over-use pointers in C++, especially not raw pointers. For pass-by-reference, prefer references to pointers (that's a C++-specific meaning of "reference" vs. "pointer"). For containers, the normal default is to use the type directly for content, though there are cases where you might want a pointer (or a smart pointer) instead.
I haven't thoroughly checked your code - there may be more issues than I caught.
i have written this small piece of Code for testing purposes:
#include <iostream>
#include "SDL2/SDL.h"
int main(int argc, char* argv[]) {
if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {
printf("Unable to initialize SDL: %s\n", SDL_GetError());
return 1;
}
// Betriebssystem ermitteln
std::string PlatFormString;
PlatFormString = SDL_GetPlatform();
std::cout << PlatFormString << "\n";
// Separator ermitteln
char Separator = '/';
if (PlatFormString == "Windows") {
Separator = '\\';
}
std::cout << "Separator: " << Separator << "\n";
// Installationspfad ermitteln
std::string InstallPath;
InstallPath = SDL_GetBasePath();
std::cout << InstallPath << "\n";
// Benutzerverzeichnis ermitteln
char* UserPath;
UserPath = SDL_GetPrefPath("TFF", "Blaster");
if (UserPath == nullptr) {
std::cout << "No Userpath aviable !! \n";
}
else {
std::cout << UserPath << "\n";
}
SDL_Quit();
return 0;
};
Under Linux eerthing works fine.
But under Windows, i am getting these strange errors ...
-------------- Build: Debug in Test (compiler: GNU GCC Compiler)---------------
g++.exe -LD:\mingw64 -LD:\mingw64\bin -LD:\mingw64\include -LD:\mingw64\include\SDL2 -LD:\mingw64\lib -o bin\Debug\Test.exe obj\Debug\src\Test.o -lmingw32 -lSDL2main -lSDL2 -lSDL2_image -lSDL2_mixer ..\..\mingw64\lib\libSDL2main.a ..\..\mingw64\lib\libSDL2.a
..\..\mingw64\lib\libSDL2.a(SDL_systimer.o): In function `timeSetPeriod':
/Users/slouken/release/SDL/SDL2-2.0.3-source/foo-x64/../src/timer/windows/SDL_systimer.c:58: undefined reference to `__imp_timeBeginPeriod'
/Users/slouken/release/SDL/SDL2-2.0.3-source/foo-x64/../src/timer/windows/SDL_systimer.c:52: undefined reference to `__imp_timeEndPeriod'
/Users/slouken/release/SDL/SDL2-2.0.3-source/foo-x64/../src/timer/windows/SDL_systimer.c:58: undefined reference to `__imp_timeBeginPeriod'
and so on. I dont know whats going on there. Can anyone help ?
I#m using Codeblocks 13.12, minGW64 (4.8.1), SDL 2.0.3 and Windows 7 64bit
You need to link against winmm.lib.
Try adding
#pragma comment(lib, "winmm.lib")
to your source.
I am posting this about a year later but for the future searchers here is the solution. Replace libSDL2.a with libSDL2.dll.a and it will compile just fine. The issue has something to do with dynamic and static linking with a windows machine or something I personally do I understand it completely but it works.
I came across the solution by reading this article: http://tech.yipp.ca/sdl/how-to-fix-libsdla-undefined-reference/
However this goes on a whole other solution I read between the lines or more particularly.
This is a really a rare problem that would occur only when you try to link with libSDL.a static library instead of the dynamic library SDL.dll. Then you have to add those library that SDL.dll normally links against which are the three above.
Given a class A with two constructors, taking initializer_list<int> and initializer_list<initializer_list<int>> respectively, then
A v{5,6};
calls the former, and
A v{{5,6}};
calls the latter, as expected. (clang3.3, apparently gcc behaves differently, see the answers. What does the standard require?)
But if I remove the second constructor, then A v{{5,6}}; still compiles and it uses the first constructor. I didn't expect this.
I thought that A v{5,6} would be the only way to access the initializer_list<int> constructor.
(I discovered this while playing around with std::vector and this question I asked on Reddit, but I created my own class A to be sure that it wasn't just a quirk of the interface for std::vector.)
I think this answer might be relevant.
Yes, this behaviour is intended, according to §13.3.1.7 Initialization
by list-initialization
When objects of non-aggregate class type T are list-initialized (8.5.4), overload resolution selects the constructor in two phases:
— Initially, the candidate functions are the initializer-list constructors (8.5.4) of the class T and the argument list consists of
the initializer list as a single argument.
— If no viable initializer-list constructor is found, overload resolution is performed again, where the candidate functions are all
the constructors of the class T and the argument list consists of the
elements of the initializer list.
In gcc I tried your example. I get this error:
error: call of overloaded 'A(<brace-enclosed initializer list>)' is ambiguous
gcc stops complaining if I use three sets of brace. i.e.:
#include <iostream>
#include <vector>
#include <initializer_list>
struct A {
A (std::initializer_list<int> il) {
std::cout << "First." << std::endl;
}
A (std::initializer_list<std::initializer_list<int>> il) {
std::cout << "Second." << std::endl;
}
};
int main()
{
A a{0}; // first
A a{{0}}; // compile error
A a2{{{0}}}; // second
A a3{{{{0}}}}; // second
}
In an attempt to mirror the vector's constructors, here are my results:
#include <iostream>
#include <vector>
#include <initializer_list>
struct A {
A (std::initializer_list<int> il) {
std::cout << "First." << std::endl;
}
explicit A (std::size_t n) {
std::cout << "Second." << std::endl;
}
A (std::size_t n, const int& val) {
std::cout << "Third." << std::endl;
}
A (const A& x) {
std::cout << "Fourth." << std::endl;
}
};
int main()
{
A a{0};
A a2{{0}};
A a3{1,2,3,4};
A a4{{1,2,3,4}};
A a5({1,2,3,4});
A a6(0);
A a7(0, 1);
A a8{0, 1};
}
main.cpp:23:10: warning: braces around scalar initializer
A a2{{0}};
^~~
1 warning generated.
First.
First.
First.
First.
First.
Second.
Third.
First.
C++11
I'm having trouble using the move constructor. I have a simple container class, called Number, whose only data member is an integer. I have the following code:
//Number.h
#ifndef NUMBER_H
#define NUMBER_H
#include <iostream>
class Number
{
public:
Number();
Number(int ipar);
Number(const Number& src);
Number(Number&& src);
private:
int num;
};
#endif
and
//Number.cpp
#include "Number.h"
Number::Number()
{
std::cout << "default ctor" << std::endl;
}
Number::Number(int ipar) : num(ipar)
{
std::cout << "integer argument ctor" << std::endl;
}
Number::Number(const Number& src) : num(src.num)
{
std::cout << "copy ctor" << std::endl;
}
Number::Number(Number&& src) : num(src.num)
{
std::cout << "move ctor" << std::endl;
}
and
//main.cpp
#include "Number.h"
using namespace std;
int main()
{
cout << "Part A:" << endl;
Number n1(1);
cout << "Part B:" << endl;
Number n2(n1);
cout << "Part C:" << endl;
Number n3{Number{n1}};
cout << "Part D:" << endl;
Number n4(Number(n1));
return 0;
}
This outputs:
Part A:
integer argument ctor
Part B:
copy ctor
Part C:
copy ctor
Part D:
Notice there is no output for Part D. The output for Parts A and B are what I expected, but the output for the others aren’t.
I expected this for Parts C and D:
Part C:
copy ctor
move ctor
Part D:
copy ctor
move ctor
Expectation for Part C:
I expected the Number{n1} part of Number n3{Number{n1}} to make a temporary nameless Number object, because there is no name between Number and the opening curly brace, by calling the copy constructor with n1. Then I expected Number n3 to be constructed by calling the move constructor with the temporary object.
Expectation for Part D:
Since this is like Part C, except with parentheses instead of curly braces, I expected this part to behave and output in the same way I expected Part C to.
Question:
Why does the actual output differ from my expectations and what is the correct way to get my desired output?
Note: If you want to compile this in Visual Studio, you need the Visual C++ Compiler November 2012 CTP or later for Visual Studio 2012 in order to support the uniform initialization syntax.
n4 is a function declaration. n3 is caused by copy elision.
Check that here I've enabled -fno-elide-constructors to avoid copy elision. n3 then shows a sequence of copy and move constructors.
There's a commented out line that tries to use n4 as an object. If you uncomment it, you'll see the compiler error telling it's a function instead.
For n4 do not be interpreted as a function declaration you could put extra parentheses around the temporary to prevent it from being viewed as a function parameter: Number n4((Number(n1))). With this and -fno-elide-constructors all you've expected happens.
Note that -fno-elide-constructors is not present as an option in MSVC.
Hello I have a program with a global function that I'd like to customize at run time. Say, there are many versions of function foo() scattered over shared libraries. Now, based on system configuration detected at run time I'd like to use function from appropriate library.
File loader.cpp:
#include <dlfcn.h>
#include <iostream>
void __attribute__((weak)) foo();
int main(int argc, char *argv[])
{
void* dl = dlopen("./other.so", RTLD_NOW | RTLD_GLOBAL);
if (!dl)
{
std::cerr << dlerror() << std::endl;
return 1;
}
if (foo)
{
foo();
}
else
{
std::cerr << "No foo?" << std::endl;
}
dlclose(dl);
return 0;
}
File other.cpp:
#include <iostream>
void foo()
{
std::cout << "FOO!" << std::endl;
}
I compile the program with
g++ -Wall -fPIC -o loaded loader.cpp -ldl
g++ -Wall -fPIC -shared -o other.so other.cpp
However the weak symbol is not overriden. Any hints?
Symbols are resolved during load time of the image in which they are referenced. So when your executable is loaded, the reference to foo is already resolved. A later dlopen won't go and rebind all symbols - it only may affect later loads.
You'll have to use dlsym instead, or set LD_PRELOAD:
martin#mira:/tmp$ LD_PRELOAD=/tmp/other.so ./loaded
FOO!
You compiled the shared lib with g++.
As a result, the name of the function is mangled:
$ nm -S other.so |grep foo
0000000000000690 000000000000002e T _Z3foov
If you make it a pure C code and compile with
gcc instead of g++, you'll find it working as you expect.
Alternatively, define it as follows:
extern "C" void foo()
{
std::cout << "FOO!" << std::endl;
}