重复使用保存箱

重复使用保存箱

由于\newsavebox{\name}将盒子注册号分配给,因此最多可能有 256 个盒子可用。完成之后\name有没有办法释放?\savebox

答案1

正常模型是分配一次框(在文档开始之前)并在定义的宏中多次使用它,因此限制通常不是问题,但是所有现代发行版都使用基于 etex 的 LaTeX 格式,在这种情况下有 32768 个寄存器可用(尽管您需要\usepackage{etex}向 latex 声明这一点并使用了解寄存器的分配方案。

答案2

正如其他人提到的,LaTeX 没有提供释放未使用寄存器的方法。这比您的示例代码所建议的要困难一些,因为您可以在需要填充的已分配寄存器列表中添加“空洞”;跟踪它们会很麻烦或很慢。

如果你发现自己需要使用很多很多你想释放的寄存器,那么etex.sty在宏下有“本地”寄存器分配

  • \loccount
  • \locdimen
  • \locskip
  • \locmuskip
  • \locbox
  • \loctoks
  • \locmarks

下面显示了一个示例;您可以看到同一个框以不同的名称被分配了两次。

\documentclass[a4paper]{article}
\usepackage{etex}
\begin{document}

\begingroup
\locbox\textbox
\savebox\textbox{this is box \the\textbox: some text}
\fbox{\usebox\textbox}
\endgroup

\begingroup
\locbox\textboxB
\savebox\textboxB{this is box \the\textboxB: some more text}
\fbox{\usebox\textboxB}
\endgroup

\end{document}

为了有效,您需要分组,但如果您对保存框有如此巨大的需求,那么您可能无论如何都会在某种程度上进行分组。

答案3

如果您使用临时框寄存器(如 \box0),则必须确保不会调用使用相同框的宏,并且必须希望更新版本或包替换永远不会使用它。但是,如果您使用 \newsavebox,那么对于使用 \newsavebox 的其他人而言,它是安全的(直到您使用 \freebox 释放它)。

\documentclass{article}

\makeatletter
\newcounter{free@boxes}% push stack counter
\newcounter{free@count}% loop counter

\global\let\old@savebox=\newsavebox% save original version

\global\chardef\free@min 255
\global\chardef\free@max 0

\newcommand*{\freebox}[1]% #1 = old savebox name
{\newif\ifgood\goodtrue%
\ifnum#1<\free@min \goodfalse\fi%
\ifnum#1>\free@max \goodfalse\fi%
\ifnum\value{free@boxes}=0\relax%
  \else\setcounter{free@count}{\value{free@boxes}}%
  \loop% check for duplicates
    \ifnum#1=\csname free@box\arabic{free@count}\endcsname
      \goodfalse%
      \setcounter{free@count}{0}%
    \else\addtocounter{free@count}{-1}\fi%
    \ifnum\value{free@count}>0 \repeat%
  \fi %
\ifgood\stepcounter{free@boxes}%
\global\expandafter\let\csname free@box\arabic{free@boxes}\endcsname#1%
\fi%
\global\chardef#1 0}

\renewcommand*{\newsavebox}[1]{% #1 = new savebox name
\ifnum\value{free@boxes}>0%
  \global\edef#1{\csname free@box\arabic{free@boxes}\endcsname}%
  \addtocounter{free@boxes}{-1}%
\else\old@savebox{#1}%
  \ifnum#1<\free@min \global\let\free@min=#1 \fi%
  \ifnum#1>\free@max \global\let\free@max=#1 \fi%
\fi}
\makeatother

\begin{document}
\newsavebox{\test}
\savebox{\test}{This is a test}
\usebox{\test}

\newsavebox{\testb}
\savebox{\testb}{This is the second test}
\usebox{\testb}

\freebox{\test}% release box registers for reuse
\freebox{\testb}

\newsavebox{\reuseb}% push stack returns second box first
\usebox{\reuseb}

\newsavebox{\reuse}
\usebox{\reuse}

The following have been reset to zero:\newline
\verb$\test$ \the\test\newline
\verb$\testb$ \the\testb

\makeatletter
The following should all equal the first box register value:\newline
\verb$\reuse$ \the\reuse\newline
\verb$\free@box1$ \the\csname free@box1\endcsname

The following should all equal the second box register value:\newline
\verb$\reuseb$ \the\reuseb\newline
\verb$\free@box2$ \the\csname free@box2\endcsname
\makeatother

\end{document}

相关内容