我最近碰到了以下情况:
#include <iostream>
int *p = 0;
int f() {
p = new int(10);
return 0;
}
void g(int x, int *y = p) {
std::cout << y << std::endl;
}
int main() {
g(f());
}
Run Code Online (Sandbox Code Playgroud)
这非常微妙,因为您通常不希望默认参数在评估函数调用期间发生变化.我不得不看一下程序集来发现这个错误.
现在我的问题是:这是否真的是未定义的行为,因为对函数参数的评估顺序没有任何保证?
c++ operator-precedence undefined-behavior default-parameters
由于我在动态加载的库中观察到了全局变量的一些奇怪行为,因此我编写了以下测试.
首先,我们需要一个静态链接的库:标题 test.hpp
#ifndef __BASE_HPP
#define __BASE_HPP
#include <iostream>
class test {
private:
int value;
public:
test(int value) : value(value) {
std::cout << "test::test(int) : value = " << value << std::endl;
}
~test() {
std::cout << "test::~test() : value = " << value << std::endl;
}
int get_value() const { return value; }
void set_value(int new_value) { value = new_value; }
};
extern test global_test;
#endif // __BASE_HPP
Run Code Online (Sandbox Code Playgroud)
和来源 test.cpp
#include "base.hpp"
test global_test = test(1);
Run Code Online (Sandbox Code Playgroud)
然后我写了一个动态加载的库: library.cpp
#include …
Run Code Online (Sandbox Code Playgroud) 以下构造的实际效果是什么:
class Base { /* ... */ };
template<class T>
class Derived : public T { /* ... */ };
int main() {
Derived<const Base> d;
// ...
}
Run Code Online (Sandbox Code Playgroud)
Derived
该类是否只能访问const
接口的-part Base
?我的第一次测试表明实际上根本没有效果.为什么?
谢谢!
编译事实背后的理性是什么?
namespace ns __attribute__((visibility("default"))) {
template<typename T>
inline int func1(const T& x) {
return x;
}
inline int func2(int x) {
return x;
}
struct test {
template<typename T>
int func3(const T &x) { return x; }
int func4(int x) { return x; }
};
}
int __attribute__((visibility("default"))) client(int x) {
ns::test t;
const int y1 = ns::func1(x);
const int y2 = ns::func2(x);
const int y3 = t.func3(x);
const int y4 = t.func4(x);
return y1 + y2 + y3 + …
Run Code Online (Sandbox Code Playgroud) 我想看到一个动态加载的库(加载了dlopen等)确实使用了自己的新的删除操作符而不是调用程序中定义的那些操作符.所以我写了下面的library.cpp
#include <exception>
#include <new>
#include <cstdlib>
#include <cstdio>
#include "base.hpp"
void* operator new(size_t size) {
std::printf("New of library called\n");
void *p=std::malloc(size);
if (p == 0) // did malloc succeed?
throw std::bad_alloc(); // ANSI/ISO compliant behavior
return p;
}
void operator delete(void* p) {
std::printf("Delete of library called\n");
std::free(p);
}
class Derived : public Base {
public:
Derived() : Base(10) { }
};
extern "C" {
Base* create() {
return new Derived;
}
void destroy(Base* p) {
delete p;
} …
Run Code Online (Sandbox Code Playgroud) 将a struct
作为C- 转发声明是否合法struct
// api.h
#ifdef __cplusplus
extern "C" {
#endif
typedef struct handle_tag handle_t;
handle_t *construct();
void destruct(handle_t *h);
void func(handle_t *h);
#ifdef __cplusplus
}
#endif
Run Code Online (Sandbox Code Playgroud)
然后将其定义为C++ - struct
即作为非POD类型?
// api.cpp
struct handle_tag {
void func();
std::string member;
};
void func(handle_t *h) {
h->func();
}
Run Code Online (Sandbox Code Playgroud)
一般意图是通过C接口获得外部可访问的opaque类型handle_t
,该类型在内部实现为C++数据类型.
头common.h
向前声明一个类Test
和一个接收成员函数指针的函数:
class Test;
void func(const Test &t, int (Test::*f)() const, int x, int y);
Run Code Online (Sandbox Code Playgroud)
在源文件中target.cpp
,我定义了这样的函数
#include "common.h"
void func(const Test &t, int (Test::*f)() const, int x, int y) {
std::cout << "f: " << (t.*f)() << ", x: " << x << ", y: " << y << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
在我的主文件中,我定义了类Test
并使用了该函数func
:
class Test {
public:
int example() const { return 1; }
};
#include "common.h"
int main() {
Test t; …
Run Code Online (Sandbox Code Playgroud) 由于我之前的 问题,我问自己:为插件系统设置C++接口是否有用?以下几点是针对它的:
delete
它们的其他对象(例如智能指针)保持,则会出现问题.std::list<T>
给插件如果你克制自己的C++语言的其余部分,你几乎最终得到"C子集".有没有关于使用C++的观点?Qt-Toolkit如何解决上述问题?
备注:我主要指的是Linux系统.不过我对其他平台上的解决方案感兴趣.
其他问题:使用C接口有什么问题?struct
s 的内存布局?应该避免C的哪些语言部分?
简短问题:LC_RPATH
库中命令的rpath是否传递到后续(和间接)动态加载的库中?
更确切地说:我已libapi.dylib
动态链接到libloader.dylib
动态加载插件libplugin.dylib
.我有:
$ otool -l lib/libapi.dylib
lib/libapi.dylib
libapi.dylib
/usr/lib/libSystem.B.dylib
@rpath/libloader.dylib
$ otool -l lib/libloader.dylib
lib/libloader.dylib
libloader.dylib
/usr/lib/libSystem.B.dylib
$ otool -l lib/plugins/libplugin.dylib
lib/plugins/libplugin.dylib:
libplugin.dylib
/usr/lib/libSystem.B.dylib
@rpath/libloader.dylib
$ otool -L lib/libapi.dylib | grep "LC_RPATH" -A2
cmd LC_RPATH
cmdsize 32
path @loader_path/ (offset 12)
Run Code Online (Sandbox Code Playgroud)
既不定义rpath命令libloader.dylib
也不libplugin.dylib
定义.并且安装名称没有任何@ rpath /或其他路径,尽管load命令中的名称前缀为@rpath /.
客户端现在加载libapi.dylib
哪个链接到哪个libloader.dylib
.此库动态加载libplugin.dylib
链接到的库libloader.dylib
.
为什么不能libplugin.dylib
加载?它退出,因为它找不到libloader.dylib
- 虽然它必须已经加载.为什么rpath @ loader_path/libapi.dylib
没有正确地传播libloader.dylib
到libplugin.dylib …
我们有以下历史
start master public
| | |
v v v
o---o-- ... --o---o---o
Run Code Online (Sandbox Code Playgroud)
不幸的是,我们在master
包含一些敏感数据的分支中做了一些提交.我们在一个名为public的独立分支中进行了修改.现在我们想要"切断" public
分支,以获得一个完整而干净的"状态",public
但没有妥协的历史部分仍然包含在内master
.换句话说,我们想要以下新历史:
start master
| |
v v
o---o-- ... --o---o
\
o <- public
Run Code Online (Sandbox Code Playgroud)
现在退房public
将导致与原始情况相同的工作树,但没有合理的历史细节.然后我们将旧分支停止master
:将其重命名为unsafe
并从新master
分支中精心设计一个新public
分支.通过这种方式,我们保留了旧的历史,unsafe
并且能够public
毫无后顾之忧地将分支机构推向公众:
start unsafe
| |
v v
o---o-- ... --o---o
\
o---o-- ... --o <-- public
\ /
o-- .. --o-- ... --o <-- master
Run Code Online (Sandbox Code Playgroud)
有什么正确的git命令来实现这一目标?
PS:当然我们可以结账start
,建立一个新的分支并在那里提交分支的整个工作树public
.但必须有一种不同的,更加迷人的git方式!
因为我需要operator&
为std::tr1::array<bool, N>
我写下以下几行
template<std::size_t N>
std::tr1::array<bool, N>
operator& (const std::tr1::array<bool, N>& a,
const std::tr1::array<bool, N>& b)
{
std::tr1::array<bool, N> result;
std::transform(a.begin(), a.end(), b.begin(), result.begin(),
std::logical_and<bool>());
return result;
}
Run Code Online (Sandbox Code Playgroud)
现在我不知道我要把这个函数放在哪个命名空间中.我认为std
命名空间是一个限制区域.用户只允许添加完全特化和重载的功能模板.将它放入全局命名空间不是"允许",以防止污染全局命名空间和与其他声明冲突.最后将此函数放入项目的命名空间不起作用,因为编译器不会在那里找到它.
我最擅长的是什么?我不想写一个新的数组类放入项目命名空间.因为在这种情况下,编译器将通过参数依赖名称查找找到正确的命名空间.或者这是唯一可行的方法,因为为现有类编写一个新的运算符意味着扩展它们的接口,这对于标准类也是不允许的?
在Windows项目中我们定义一个接口类
class Interface {
public:
virtual ~Interface() { }
virtual void func() = 0;
};
Run Code Online (Sandbox Code Playgroud)
和一个工厂函数
__declspec(dllexport) Interface *construct();
Run Code Online (Sandbox Code Playgroud)
在 DLL 内。Interface
当然,DLL 内部有具体的专门化,但我们不导出它。不过我们可以在 DLL 之外使用它。这是如何运作的?vftable
由 构造的实例由construct()
指向 DLL 未导出的函数的函数指针组成。这种方法可以接受还是或多或少是一种黑客行为?
我写了以下程序
#include <iostream>
template<typename C, typename Res, typename... Args>
class bind_class_t {
private:
Res (C::*f)(Args...);
C *c;
public:
bind_class_t(Res (C::*f)(Args...), C* c) : f(f), c(c) { }
Res operator() (Args... args) {
return (c->*f)(args...);
}
};
template<typename C, typename Res, typename... Args>
bind_class_t<C, Res, Args...>
bind_class(Res (C::*f)(Args...), C* c) {
return bind_class<C, Res, Args...>(f, c);
}
class test {
public:
int add(int x, int y) {
return x + y;
}
};
int main() {
test t;
// bind_class_t<test, int, …
Run Code Online (Sandbox Code Playgroud) c++ ×10
c ×2
g++ ×2
gcc ×2
templates ×2
visual-c++ ×2
allocation ×1
branch ×1
cmake ×1
const ×1
dllexport ×1
dyld ×1
elf ×1
git ×1
linux ×1
mach-o ×1
macos ×1
namespaces ×1
overriding ×1
plugins ×1
rpath ×1
variadic ×1
visibility ×1