C++:栈帧、命名空间、引用

article/2025/9/4 9:36:55

一、前置知识

1.1、栈区(Stack)

1.1.1、内存分配与回收机制

  • 分配方式​​:由编译器自动管理,通过调整栈指针(ESP/RSP)实现。
  1. 函数调用时,栈指针下移(栈从高地址向低地址增长),分配栈帧空间。
  2. 函数返回时,栈指针上移,回收栈帧(​​不擦除数据,仅移动指针​​)。
  • ​存储内容​​:
  1. 局部变量(非 static
  2. 函数参数(x86 下部分通过栈传递)
  3. 返回地址(Caller 的 EIP/RIP
  4. 上一栈帧的基址(EBP/RBP

1.1.2、栈帧销毁时的行为

  • ​栈指针回退​​:RET 指令执行后,栈指针恢复到调用前的状态。
  • ​内存未清零​​:栈内存只是“逻辑释放”,数据仍残留(可能被后续函数覆盖)。
  • ​局部变量失效​​:
  1. 普通变量(如 int x):直接失效,访问会导致未定义行为(UB)。
  2. 指针变量(如 int* p):若指向栈内存(如 p = &x),则成为 ​​悬空指针。

1.1.3、底层汇编视角

; 函数调用时
push ebp          ; 保存调用者的栈基址
mov ebp, esp      ; 设置当前栈帧基址
sub esp, 16       ; 分配16字节栈空间(局部变量); 函数返回时
mov esp, ebp      ; 恢复栈指针(销毁栈帧)
pop ebp           ; 恢复调用者的栈基址
ret               ; 返回

1.1.4、典型问题

  • ​栈溢出(Stack Overflow)​​:递归过深或局部变量过大(如 int a[1000000])导致栈耗尽。
  • ​返回栈地址的陷阱​:
int* foo() {int x = 42;return &x;  // 返回局部变量地址(危险!)
}
int* p = foo(); // p现在是悬垂指针

2.1、堆区(Heap)

2.1.1、内存分配与回收机制

  • ​分配方式​​:手动管理(malloc/freenew/delete)。
  1. malloc 调用 brk 或 mmap 向操作系统申请内存。
  2. 堆内存由 ​​内存管理器(如 glibc 的 ptmalloc)​​ 维护,可能存在碎片。
  • ​存储内容​​:
  1. 动态分配的数据(如 int* p = malloc(sizeof(int)))。
  2. 需要显式释放,否则泄漏。

2.1.2、栈帧销毁时的行为

  • ​堆内存不受影响​​:
  1. 栈帧销毁仅回收栈上的指针变量(如 int* p),但堆内存仍存在。
  2. 若未调用 free,则内存泄漏。
  3. 若已 free 但继续访问,则导致 ​​野指针​​。
  • ​指针变量的生命周期​​:
void func() {int* p = malloc(sizeof(int)); // p在栈上,指向堆内存*p = 100;
} // p被销毁,但堆内存未释放(泄漏!)

2.1.3、底层实现(Linux glibc)

  • malloc 内部可能调用 brk(扩展堆)或 mmap(大内存映射)。
  • free 不会立即归还内存给 OS,而是由内存池管理(提高复用效率)。

2.1.4、典型问题

  • 内存泄漏
void leak() {while (1) malloc(1024); // 持续泄漏,最终OOM
}
  • 双重释放
int* p = malloc(sizeof(int));
free(p);
free(p); // 崩溃或安全漏洞(如Use-After-Free)
  • 野指针
int* p = malloc(sizeof(int));
free(p);
*p = 42; // 未定义行为(可能崩溃或数据损坏)

3.1、静态区(Static/全局存储区)

3.1.1、内存分配与回收机制

  • ​分配方式​​:
  1. 全局变量​​:程序启动时分配,程序结束时释放。
  2. ​静态变量​​(static 修饰):首次执行到定义处时初始化(C++11 后线程安全)。
  • ​存储位置​​:
  1. .data 段(已初始化的全局/静态变量)
  2. .bss 段(未初始化的全局/静态变量,默认零值)
  3. 常量区(如字符串字面量 "hello"

3.1.2、栈帧销毁时的行为

  • ​完全不受影响​​:
  1. 静态变量的生命周期与程序相同,栈帧销毁后仍可访问。
  2. 局部静态变量(static int x)仅作用域受限,但内存持久。
void counter() {static int count = 0; // 只初始化一次count++;printf("%d\n", count);
}
// 多次调用counter()会输出递增的count

3.1.3、底层实现

  • 编译时确定地址,运行时直接通过固定地址访问。
  • 示例(反汇编):
mov eax, DWORD PTR [0x404000] ; 访问静态变量

3.1.4、典型问题

  • 线程安全问题
static int shared = 0;
void thread_func() {shared++; // 多线程竞争(需加锁)
}
  • 初始化顺序问题
extern int a; // 定义在其他文件
static int b = a + 1; // a的初始化顺序不确定

4.1、销毁与返回值传递的顺序

就以这段代码为例讲解一下两者之间的关系:

int* foo() {int x = 42;return &x;  // 返回局部变量地址(危险!)
}
int* p = foo(); // p现在是悬空指针

结论:先传递,后销毁。【先将返回值存储在临时变量里面(有的话),再销毁函数栈帧】

4.1.1、执行顺序

  • ​计算返回值​​:

  1. return &x; 会先计算 x 的地址(即栈上的某个位置)。

  2. 这个地址会被 ​​临时存储​​(通常在寄存器 EAX/RAX 中,或者某个临时内存位置)。
  • ​销毁栈帧​​:

  1. 函数 foo 的栈帧被销毁(mov esp, ebp + pop ebp)。

  2. 局部变量 x 的内存被“逻辑释放”(栈指针回退,但数据可能残留)。

  • ​返回值传递​​:

  1. 计算好的地址(&x)从临时存储(如 EAX)传递给调用者 p

  2. 此时 p 指向的 x 的地址 ​​已经失效​​(因为栈帧已销毁)。

4.1.2、为什么返回值还能“正确”访问?(未定义行为的陷阱)

即使 p 是悬空指针,以下代码可能偶尔“工作”:

int* p = foo();
printf("%d\n", *p);  // 可能输出42(未定义行为!)

原因:

  • 栈内存未被其他数据覆盖(残留值仍在、在下文介绍引用的时候,也会涉及到这一点)。
  • ​但这不合法​​,任何修改(如调用其他函数)可能导致崩溃或数据错误。

5.5、总结

特性栈区堆区静态区
分配方式自动(编译器)手动(malloc、free)自动(程序启动,首次使用)
释放时机函数返回时显示调用free程序结束时
访问速度极快(寄存器,栈指针访问)较慢(间接寻址)快(固定寻址)
生命周期函数作用域内手动控制程序整个生命周期
线程安全是(每个线程独立)需同步需同步(全局变量)
典型问题栈溢出,悬空指针内存泄漏,野指针初始化顺序,线程竞争

二、C++关键字(C++98)

C++总计63个关键字,C语言32个关键字
ps:下面我们只是看一下C++有多少关键字,不对关键字进行具体的讲解。
asmdoifreturntrycontinue
autodoubleinlineshorttypedeffor
booldynamic_castintsignedtypeidpublic
breakelselongsizeoftypenamethrow
caseenummutablestaticunionwchar_t
catchexplicitnamespacestatic_castunsigneddefault
charexportnewstructusingfriend
classexternoperatorswitchvirtualregister
constfalseprivatetemplatevoidtrue
const_castfloatprotectedthisvolatilewhile
deletegotoreinterpret_cat

三、命名空间

在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。
#include <stdio.h>
#include <stdlib.h>
int rand = 10;
// C语言没办法解决类似这样的命名冲突问题,所以C++提出了namespace来解决
int main()
{printf("%d\n", rand);return 0;
}
// 编译后后报错:error C2365: “rand”: 重定义;以前的定义是“函数”

3.1、命名空间定义

定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名空间的成员。
// ljt是命名空间的名字,一般开发中是用项目名字做命名空间名。
// 1. 正常的命名空间定义
namespace ljt
{// 命名空间中可以定义变量/函数/类型int rand = 10;int Add(int left, int right){return left + right;}struct Node{struct Node* next;int val;};
}
//2. 命名空间可以嵌套
// test.cpp
namespace N1
{int a;int b;int Add(int left, int right){return left + right;}namespace N2{int c;int d;int Sub(int left, int right){return left - right;}}
}
//3. 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。
// ps:一个工程中的test.h和上面test.cpp中两个N1会被合并成一个
// test.h
namespace N1
{int Mul(int left, int right){return left * right;}
}
注:一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中。

3.2、命名空间的使用

命名空间中成员该如何使用呢?比如:
namespace ljt
{// 命名空间中可以定义变量/函数/类型int a = 0;int b = 1;int Add(int left, int right){return left + right;}struct Node{struct Node* next;int val;};
}
int main()
{// 编译报错:error C2065: “a”: 未声明的标识符printf("%d\n", a);return 0;
}
命名空间的使用有三种方式:
  • 加命名空间名称及作用域限定符
int main()
{printf("%d\n", N::a);return 0;    
}
  • 使用using将命名空间中某个成员引入(工程中常用)
using N::b;
int main()
{printf("%d\n", N::a);printf("%d\n", b);return 0;    
}
  • 使用using namespace 命名空间名称 引入
using namespce N;
int main()
{printf("%d\n", N::a);printf("%d\n", b);Add(10, 20);return 0;    
}

四、引用

4.1、引用的概念

引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空
间,它和它引用的变量共用同一块内存空间。

类型& 引用变量名(对象名) = 引用实体;

void TestRef()
{int a = 10;int& ra = a;//<====定义引用类型printf("%p\n", &a);printf("%p\n", &ra);
}
注意:引用类型必须和引用实体同种类型

4.2、引用特性

  • 引用在定义时必须初始化
  • 一个变量可以有多个引用
  • 引用一旦引用一个实体,再不能引用其他实体
#include <iostream>
//using std::cout;using namespace std;
int main()
{int a = 5;int& b = a;cout << &a << " " << & b << endl;//引用即取别名,内存地址是一样的//引用一旦引用一个实体,再不能引用其他实体int x = 10;a = x;//并没有改变引用,只是赋值。cout << a << " " << b << endl;return 0;
}
打印:

4.3、常引用

void TestConstRef()
{const int a = 10;//int& ra = a;   // 该语句编译时会出错,a为常量const int& ra = a;// int& b = 10; // 该语句编译时会出错,b为常量const int& b = 10;double d = 12.34;//int& rd = d; // 该语句编译时会出错,类型不同const int& rd = d; 
}

注:对于(常)引用,你只要明白引用拥有两个权限,一个是写(改写),另一个是读。如果我写的是注释中的那种形式,那么对于一个常数有了写与读的权限,但是常数它只能读,不能改写,则权限被你放大了,需要加上const修饰,限制写的权限。

int main()
{// 不可以// 引用过程中,权限不能放大const int a = 0;//int& b = a;// 可以,c拷贝给d,没有放大权限,因为d的改变不影响cconst int c = 0;int d = c;// 不可以// 引用过程中,权限可以平移或者缩小int x = 0;int& y = x;const int& z = x;++x;++y;cout << z << endl;//++z;//常值引用const int& m = 10;double dd = 1.11;int ii = dd;const int& rii = dd;return 0;
}int func1()
{static int x = 0;return x;
}int& func2()
{static int x = 0;return x;
}int main()
{//int& ret1 = func1();  // 权限放大//const int& ret1 = func1(); // 权限平移// int ret1 = func1();  // 拷贝int& ret2 = func2();		// 权限平移const int& rret2 = func2();  // 权限缩小return 0;
}

像这些代码,本质上都是一样的,无论是引用作为返回值,还是什么情况,都存在权限的放大,平移,缩小的问题,看你的函数想实现的是什么功能,写 or 读 or 写 + 读,再来判断是否要加const修饰。

4.4、使用场景

  • 做参数
引用做参数(减少拷贝提高效率)(大对象/深拷贝类对象)
#include <iostream>
using namespace std;void swap1(int x, int y)
{int temp = x;x = y;y = temp;
}void swap2(int* x, int* y)
{int temp = *x;*x = *y;*y = temp;
}void swap3(int& x, int& y)
{int temp = x;x = y;y = temp;
}
int main()
{int a = 1, b = 2;//传值cout << "a = " << a << " " << "b = " << b << endl;swap1(a, b);cout << "a = " << a << " " << "b = " << b << endl;//指针传参(C语言)cout << "a = " << a << " " << "b = " << b << endl;swap2(&a, &b);cout << "a = " << a << " " << "b = " << b << endl;//引用做参数cout << "a = " << a << " " << "b = " << b << endl;swap3(a, b);cout << "a = " << a << " " << "b = " << b << endl;return 0;
}

三种方式可以比较一下,传值,C语言传地址,C++引用。

  • 做返回值
//引用做返回值  (减少拷贝提高效率)(大对象/深拷贝类对象--什么是深拷贝以后会讲)
//引用做返回值   修改返回值+获取返回值(权限)
//做返回值
#include <iostream>
using namespace std;
//传值返回
int count()
{static int n = 0;n++;return n;
}int main()
{//并不是直接把值返回给ret,栈帧销毁的时候,先把数据放在临时变量里面,再赋值给retint ret = count();return 0;
}

解释在注释中,下面讲一个与栈帧联系比较紧密的代码。

#include <iostream>
#include <ctime>
#include <cassert>
using namespace std;int& Count(int x)
{int n = x;n++;return n;
}int main()
{int& ret = Count(10);cout << ret << endl;rand();Count(20);cout << ret << endl;return 0;
}

这段代码乍一看好像没有问题,确实,如果栈帧没有销毁干净,有数据残留,是可以正常打印11,21的。但是,这段代码大错特错,问题一堆,BUG也非常难以察觉。

首先你要明白返回值是int&类型,返回的时候,没有临时变量的产生(int作为返回值时候有),这段Count函数代码返回的是n的引用,但是n是int类型,内存开辟在栈区,函数结束,生命周期结束,后续会造成非法访问(UB:未定义行为),而你的接收值也是int&类型,即是引用的引用,本质上还是指那个销毁的变量,你现在要去打印ret,一个已经被销毁的变量,如果栈帧销毁干净,没有数据残留,就是随机值,但也有可能成功打印,栈帧未销毁干净。

其次,如果你中间没有调用其他函数(如printf,rand等等),你再去调用Count函数,它大概率还会开辟在原来的那块栈区,还是有可能打印出21,但也可能是随机值,道理和上面那段话一样。但如果你中间加了其他函数,就会存在栈帧的覆盖,将原来Count的栈帧占据,使再次调用Count的时候,是一块新的栈空间,会导致随机值的产生,但也有可能打印出21,就是并没有占据核心的栈区部分。

总之,这种写法非常危险,漏洞百出,在大型项目里还非常难察觉,尽量减少这种写法。

也可以看一下下面这张图来理解:

注意:如果函数返回时,出了函数作用域,如果返回对象还在(还没还给系统),则可以使用 引用返回,如果已经还给系统了,则必须使用传值返回。

4.5、传值、传引用的效率

以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。
typedef struct A
{int a[2000];
}A;//效率问题
//拷贝//​​test1(a)(传值调用)​​:
//每次调用都会在栈上复制整个 A 结构体(800KB)。
//10000 次循环 = 8GB 数据拷贝(非常低效)。//​​test2(a)(传引用)​​:
//只传递指针(8字节),没有数据拷贝。
//10000 次循环 = 80KB 数据传递(高效)
void test1(A a)
{}//不需要拷贝
void test2(A& a)
{}void TestRefAndValue()
{A a;// 以值作为函数参数size_t begin1 = clock();for (size_t i = 0; i < 10000; ++i)test1(a);size_t end1 = clock();// 以引用作为函数参数size_t begin2 = clock();for (size_t i = 0; i < 10000; ++i)test2(a);size_t end2 = clock();// 分别计算两个函数运行结束后的时间cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
}int main()
{TestRefAndValue();return 0;
}

 通过上述代码的比较,发现传值和指针在作为传参以及返回值类型上效率相差很大

4.6、引用和指针的区别

语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。
int main()
{int a = 10;int& ra = a;cout << "&a = " << &a << endl;cout << "&ra = " << &ra << endl;return 0;
}
底层实现上实际是有空间的,因为引用是按照指针方式来实现的。
int main()
{int a = 10;int& ra = a;ra = 20;int* pa = &a; *pa = 20;return 0;
}
我们来看下引用和指针的汇编代码对比:

 引用和指针的不同点:

  • 引用概念上定义一个变量的别名,指针存储一个变量地址。
  • 引用在定义时必须初始化,指针没有要求
  • 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
  • 没有NULL引用,但有NULL指针
  • 在sizeof中含义不同引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)
  • 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
  • 有多级指针,但是没有多级引用
  • 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
  • 引用比指针使用起来相对更安全

http://www.hkcw.cn/article/XdyhKvlIax.shtml

相关文章

【HarmonyOS 5】鸿蒙应用px,vp,fp概念详解

【HarmonyOS 5】鸿蒙应用px&#xff0c;vp&#xff0c;fp概念详解 一、前言 目前的鸿蒙开发者&#xff0c;大多数是从前端或者传统移动端开发方向&#xff0c;转到鸿蒙应用开发方向。 前端开发同学对于开发范式很熟悉&#xff0c;但是对于工作流程和开发方式是会有不适感&am…

[Rust_1] 环境配置 | vs golang | 程序运行 | 包管理

目录 Rust 环境安装 GoLang和Rust 关于Go 关于Rust Rust vs. Go&#xff0c;优缺点 GoLang的优点 GoLang的缺点 Rust的优点 Rust的缺点 数据告诉我们什么&#xff1f; Rust和Go的主要区别 (1) 性能 (2) 并发性 (3) 内存安全性 (4) 开发速度 (5) 开发者体验 Ru…

Codeforces Round 1024 (Div. 2)

Problem - A - Codeforces 思维题&#xff1a; 如果n不能整除p&#xff0c;就会多出一部分&#xff0c;这个部分可以作为调和者&#xff0c;使整个数组符合要求。 如果n能整除p&#xff0c;没有调和空间&#xff0c;只有看n/p*qm 来看代码&#xff1a; #include <bits/s…

【东枫科技】KrakenSDR 天线阵列设置

标准测向需要五根相同的全向天线。您可以折衷使用更少的天线&#xff0c;但为了获得最佳性能&#xff0c;我们建议使用全部五根天线。这些天线通常是磁铁安装的鞭状天线&#xff0c;或偶极子天线。我们建议始终使用均匀圆形阵列 (UCA) 天线&#xff0c;因为它可以确定来自各个方…

包含Javascript的HTML静态页面调取本机摄像头

在实际业务开发中&#xff0c;需要在带有摄像头的工作机上拍摄施工现场工作过程的图片&#xff0c;然后上传到服务器备存。 这便需要编写可以运行在浏览器上的代码&#xff0c;并在代码中实现Javascript调取摄像头、截取帧保存为图片的功能。 为了使用户更快掌握JS调取摄像头…

2023年6月第三套第二篇

找和脑子有关系的rather than 不是的意思&#xff0c;不用看 instead表示递进的解释 even when即使不重要&#xff0c;看前方主句 d选项是even when和前方主句的杂糅&#xff0c;往往是错的 instead of 而不是 这道题&#xff0c;有的人觉得避免模仿这时候你会笑&#xff0c;所…

Redis的大Key问题如何解决?

大家好&#xff0c;我是锋哥。今天分享关于【Redis的大Key问题如何解决&#xff1f;】面试题。希望对大家有帮助&#xff1b; Redis的大Key问题如何解决&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Redis中的“大Key”问题是指某个键的值占用了过多…

magic-api配置Git插件教程

一、配置gitee.com 1&#xff0c;生成rsa密钥&#xff0c;在你的电脑右键使用管理员身份运行&#xff08;命令提示符&#xff09;&#xff0c;执行下面命令 ssh-keygen -t rsa -b 2048 -m PEM一直按回车键&#xff0c;不需要输入内容 找到 你电脑中的~/.ssh/id_rsa.pub 文件…

Virtuoso中对GDS文件进行工艺库转换的方法

如果要对相同工艺节点下进行性能评估&#xff0c;可以尝试将一个厂商的GDS文件转换到另一个厂商&#xff0c;不过要注意的是不同厂商&#xff08;比如SMIC和TSMC&#xff09;之间的DRC规则&#xff0c;尽量采用两个DRC中的约束较为紧张的厂商进行设计&#xff0c;以免转换到另外…

【二】9.关于设备树简介

1.什么是设备树&#xff1a; &#xff08;DTS&#xff09;采用树形结构描述扳级设备&#xff0c;也就是开发板上的设备信息&#xff0c;每个设备都是一个节点。 一个SOC可以做出很多不同的板子&#xff0c;这些不同的板子肯定是有共同的信息&#xff0c;将这些共同的信息提取出…

VSCode远程开发-本地SSH隧道保存即时修改

工作环境是一个网站团队几人同时在改&#xff0c;为了减少冲突&#xff0c;我们选择在自己公司服务器上先部署一版线上通用&#xff0c;再连接到不同的本地&#xff0c;这样我们团队可以在线上即时看到他人修改的结果&#xff0c;不用频繁拉取提交推送代码 在线上服务器建一个…

Embedded IDE下载及调试

安装cortex_debug插件 我这边用jlink烧录&#xff0c;其他的根据你自己的来 jlink路径在左下角齿轮设置里 设置位置&#xff1a; 芯片名称配置的都是自动生成的&#xff0c;在eide.json的这里改为你jflash芯片包的设置 调试里也会自动生成一个cortex_debug的调试选项 点旁边的…

lua注意事项

感觉是lua的一大坑啊&#xff0c;它还不如函数内部就局部变量呢 注意函数等内部&#xff0c;全部给加上local得了

【第4章 图像与视频】4.4 离屏 canvas

文章目录 前言为什么要使用 offscreenCanvas为什么要使用 OffscreenCanvas如何使用 OffscreenCanvas第一种使用方式第二种使用方式 计算时长超过多长时间适合用Web Worker 前言 在 Canvas 开发中&#xff0c;我们经常需要处理复杂的图形和动画&#xff0c;这些操作可能会影响页…

长安链起链调用合约时docker ps没有容器的原因

在调用这个命令的时候&#xff0c;发现并没有出现官方预期的合约容器&#xff0c;这是因为我们在起链的时候没有选择用docker的虚拟环境&#xff0c;实际上这不影响后续的调用&#xff0c;如果想要达到官方的效果那么你只需要在起链的时候输入yes即可&#xff0c;如图三所示

表中如何插入数据!扩展技能边界

insert语句向表中添加行。认识命令就行&#xff0c;使用时可以问AI帮忙写。 一.按顺序插入行 向上次新建的天气表&#xff0c;插入行。 insert into weather values (1,北京, 1, 37, 0.55, 2025-05-12); --按顺序依次写 insert into weather values (2,上海, 10, 41, …

三轴云台之抗扰动技术篇

三轴云台的抗扰动技术是保障其在复杂动态环境下实现稳定拍摄的核心&#xff0c;其技术体系涵盖机械结构优化、传感器融合算法、控制策略设计及动态补偿机制等多个层面。 一、抗扰动技术核心原理 多轴解耦与独立控制 俯仰轴&#xff08;Pitch&#xff09;、横滚轴&#xff08…

财管4-债务资本成本普通股资本成本的估计

1.债务资本成本 1) 未来成本 2) 期望成本 3) 长期债务成本 2.税前债务资本成本估计 2.1 各种方法 适用方法适用条件到期收益率公司目前有上市发行的长期债券可比公司 虽然没有上市债券&#xff0c;但可以找到一个拥有可交易债券的可比公司作为参照物&#xff1b;使…

【25-cv-05935】Keith律所代理(绿色巴士图)版权维权案

绿色巴士版权图 案件号&#xff1a;25-cv-05935 立案时间&#xff1a;2025年5月28日 原告&#xff1a;Alena Pavluchenko d/b/a Ellen Paul Art 代理律所&#xff1a;Keith 原告介绍 原告是科德角海滨的一名艺术家&#xff0c;擅长以水彩、书法和浮木雕刻记录生活。她通过…

登山第二十三梯:有序点云平面快速分割——35Hz帧速前进

文章目录 一 摘要 二 资源 三 内容 一 摘要 3D 点云中的实时平面提取对于许多机器人应用至关重要。作者提出了一种新颖的算法&#xff0c;用于在从 Kinect 传感器等设备获得的有组织的点云中实时可靠地检测多个平面。通过在图像空间中将这样的点云均匀地划分为不重叠的点组&…